Skip to content

Commit b3861c8

Browse files
committed
Revert System changes and consume fs directly
1 parent 5733e40 commit b3861c8

File tree

10 files changed

+133
-111
lines changed

10 files changed

+133
-111
lines changed

src/compiler/commandLineParser.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,8 @@ namespace ts {
201201
name: "generateTrace",
202202
type: "string",
203203
isFilePath: true,
204-
paramType: Diagnostics.FILE_OR_DIRECTORY,
204+
isCommandLineOnly: true,
205+
paramType: Diagnostics.DIRECTORY,
205206
category: Diagnostics.Advanced_Options,
206207
description: Diagnostics.Generates_an_event_trace_and_a_list_of_types
207208
},

src/compiler/sys.ts

+3-26
Original file line numberDiff line numberDiff line change
@@ -1047,13 +1047,11 @@ namespace ts {
10471047
args: string[];
10481048
newLine: string;
10491049
useCaseSensitiveFileNames: boolean;
1050-
write(s: string, fd?: number): void;
1050+
write(s: string): void;
10511051
writeOutputIsTTY?(): boolean;
10521052
readFile(path: string, encoding?: string): string | undefined;
10531053
getFileSize?(path: string): number;
10541054
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
1055-
openFile(path: string, mode: "w"): number | undefined;
1056-
closeFile(fd: number): void;
10571055

10581056
/**
10591057
* @pollingInterval - this parameter is used in polling-based watchers and ignored in watchers that
@@ -1185,33 +1183,12 @@ namespace ts {
11851183
args: process.argv.slice(2),
11861184
newLine: _os.EOL,
11871185
useCaseSensitiveFileNames,
1188-
write(s: string, fd?: number): void {
1189-
if (fd) {
1190-
_fs.writeSync(fd, s);
1191-
}
1192-
else {
1193-
process.stdout.write(s);
1194-
}
1186+
write(s: string): void {
1187+
process.stdout.write(s);
11951188
},
11961189
writeOutputIsTTY() {
11971190
return process.stdout.isTTY;
11981191
},
1199-
openFile: (path, mode) => {
1200-
try {
1201-
return _fs.openSync(path, mode);
1202-
}
1203-
catch {
1204-
return undefined;
1205-
}
1206-
},
1207-
closeFile: (fd) => {
1208-
try {
1209-
_fs.closeSync(fd);
1210-
}
1211-
catch {
1212-
// ignore
1213-
}
1214-
},
12151192
readFile,
12161193
writeFile,
12171194
watchFile,

src/compiler/tracing.ts

+110-21
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,83 @@
11
/*@internal*/
22
/** Tracing events for the compiler. */
33
namespace ts.tracing {
4-
type WriteFn = (data: string) => void;
4+
let fs: typeof import("fs") | false | undefined;
55

6-
let write: WriteFn | undefined;
6+
let traceCount = 0;
7+
let traceFd: number | undefined;
78

8-
/** Enables (and resets) tracing events for the compiler. */
9-
export function startTracing(w: WriteFn) {
10-
write = w;
11-
write(`[\n`);
9+
let legendPath: string | undefined;
10+
const legend: TraceRecord[] = [];
11+
12+
/** Starts tracing for the given project (unless the `fs` module is unavailable). */
13+
export function startTracing(configFilePath: string | undefined, traceDir: string, isBuildMode: boolean) {
14+
Debug.assert(!traceFd, "Tracing already started");
15+
16+
if (fs === undefined) {
17+
try {
18+
fs = require("fs");
19+
}
20+
catch {
21+
fs = false;
22+
}
23+
}
24+
25+
if (!fs) {
26+
return;
27+
}
28+
29+
if (legendPath === undefined) {
30+
legendPath = combinePaths(traceDir, "legend.json");
31+
}
32+
33+
// Note that writing will fail later on if it exists and is not a directory
34+
if (!fs.existsSync(traceDir)) {
35+
fs.mkdirSync(traceDir, { recursive: true });
36+
}
37+
38+
const countPart = isBuildMode ? `.${++traceCount}` : ``;
39+
const tracePath = combinePaths(traceDir, `trace${countPart}.json`);
40+
const typesPath = combinePaths(traceDir, `types${countPart}.json`);
41+
42+
legend.push({
43+
configFilePath,
44+
tracePath,
45+
typesPath,
46+
});
47+
48+
traceFd = fs.openSync(tracePath, "w");
49+
fs.writeSync(traceFd, `[\n`);
1250
}
1351

14-
/** Disables tracing events for the compiler. */
15-
export function stopTracing() {
52+
/** Stops tracing for the in-progress project and dumps the type catalog (unless the `fs` module is unavailable). */
53+
export function stopTracing(typeCatalog: readonly Type[]) {
54+
if (!traceFd) {
55+
Debug.assert(!fs, "Tracing is not in progress");
56+
return;
57+
}
58+
59+
Debug.assert(fs);
60+
1661
// This both indicates that the trace is untruncated and conveniently
1762
// ensures that the last array element won't have a trailing comma.
18-
write?.(`{"pid":1,"tid":1,"ph":"i","ts":${1000 * timestamp()},"name":"done","s":"g"}\n`);
19-
write?.(`]\n`);
20-
write = undefined;
63+
fs.writeSync(traceFd, `{"pid":1,"tid":1,"ph":"i","ts":${1000 * timestamp()},"name":"done","s":"g"}\n`);
64+
fs.writeSync(traceFd, `]\n`);
65+
66+
fs.closeSync(traceFd);
67+
traceFd = undefined;
68+
69+
if (typeCatalog) {
70+
dumpTypes(typeCatalog);
71+
}
72+
else {
73+
// We pre-computed this path for convenience, but clear it
74+
// now that the file won't be created.
75+
legend[legend.length - 1].typesPath = undefined;
76+
}
2177
}
2278

2379
export function isTracing() {
24-
return !!write;
80+
return !!traceFd;
2581
}
2682

2783
export const enum Phase {
@@ -33,15 +89,25 @@ namespace ts.tracing {
3389
}
3490

3591
export function begin(phase: Phase, name: string, args: object) {
92+
if (!traceFd) {
93+
return;
94+
}
95+
Debug.assert(fs);
96+
3697
performance.mark("beginTracing");
37-
write?.(`{"pid":1,"tid":1,"ph":"B","cat":"${phase}","ts":${1000 * timestamp()},"name":"${name}","args":{ "ts": ${JSON.stringify(args)} }},\n`);
98+
fs.writeSync(traceFd, `{"pid":1,"tid":1,"ph":"B","cat":"${phase}","ts":${1000 * timestamp()},"name":"${name}","args":{ "ts": ${JSON.stringify(args)} }},\n`);
3899
performance.mark("endTracing");
39100
performance.measure("Tracing", "beginTracing", "endTracing");
40101
}
41102

42103
export function end() {
104+
if (!traceFd) {
105+
return;
106+
}
107+
Debug.assert(fs);
108+
43109
performance.mark("beginTracing");
44-
write?.(`{"pid":1,"tid":1,"ph":"E","ts":${1000 * timestamp()}},\n`);
110+
fs.writeSync(traceFd, `{"pid":1,"tid":1,"ph":"E","ts":${1000 * timestamp()}},\n`);
45111
performance.mark("endTracing");
46112
performance.measure("Tracing", "beginTracing", "endTracing");
47113
}
@@ -53,13 +119,18 @@ namespace ts.tracing {
53119
};
54120
}
55121

56-
export function dumpTypes(types: readonly Type[], write: WriteFn) {
122+
function dumpTypes(types: readonly Type[]) {
123+
Debug.assert(fs);
124+
57125
performance.mark("beginDumpTypes");
58126

59-
const numTypes = types.length;
127+
const typesPath = legend[legend.length - 1].typesPath!;
128+
const typesFd = fs.openSync(typesPath, "w");
129+
130+
// Cleverness: no line break here so that the type ID will match the line number
131+
fs.writeSync(typesFd, "[");
60132

61-
// Cleverness: no line break hear so that the type ID will match the line number
62-
write("[");
133+
const numTypes = types.length;
63134
for (let i = 0; i < numTypes; i++) {
64135
const type = types[i];
65136
const objectFlags = (type as any).objectFlags;
@@ -127,14 +198,32 @@ namespace ts.tracing {
127198
display,
128199
};
129200

130-
write(JSON.stringify(descriptor));
201+
fs.writeSync(typesFd, JSON.stringify(descriptor));
131202
if (i < numTypes - 1) {
132-
write(",\n");
203+
fs.writeSync(typesFd, ",\n");
133204
}
134205
}
135-
write("]\n");
206+
207+
fs.writeSync(typesFd, "]\n");
208+
209+
fs.closeSync(typesFd);
136210

137211
performance.mark("endDumpTypes");
138212
performance.measure("Dump types", "beginDumpTypes", "endDumpTypes");
139213
}
214+
215+
export function dumpLegend() {
216+
if (!legendPath) {
217+
return;
218+
}
219+
Debug.assert(fs);
220+
221+
fs.writeFileSync(legendPath, JSON.stringify(legend));
222+
}
223+
224+
interface TraceRecord {
225+
configFilePath?: string;
226+
tracePath: string;
227+
typesPath?: string;
228+
}
140229
}

src/executeCommandLine/executeCommandLine.ts

+12-27
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,7 @@ namespace ts {
456456
updateSolutionBuilderHost(sys, cb, buildHost);
457457
const builder = createSolutionBuilder(buildHost, projects, buildOptions);
458458
const exitStatus = buildOptions.clean ? builder.clean() : builder.build();
459+
tracing.dumpLegend();
459460
return sys.exit(exitStatus);
460461
}
461462

@@ -476,7 +477,7 @@ namespace ts {
476477
const currentDirectory = host.getCurrentDirectory();
477478
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames());
478479
changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, currentDirectory, getCanonicalFileName));
479-
enableStatisticsAndTracing(sys, options);
480+
enableStatisticsAndTracing(sys, options, /*isBuildMode*/ false);
480481

481482
const programOptions: CreateProgramOptions = {
482483
rootNames: fileNames,
@@ -504,7 +505,7 @@ namespace ts {
504505
config: ParsedCommandLine
505506
) {
506507
const { options, fileNames, projectReferences } = config;
507-
enableStatisticsAndTracing(sys, options);
508+
enableStatisticsAndTracing(sys, options, /*isBuildMode*/ false);
508509
const host = createIncrementalCompilerHost(options, sys);
509510
const exitStatus = ts.performIncrementalCompilation({
510511
host,
@@ -541,7 +542,7 @@ namespace ts {
541542
host.createProgram = (rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences) => {
542543
Debug.assert(rootNames !== undefined || (options === undefined && !!oldProgram));
543544
if (options !== undefined) {
544-
enableStatisticsAndTracing(sys, options);
545+
enableStatisticsAndTracing(sys, options, /*isBuildMode*/ true);
545546
}
546547
return compileUsingBuilder(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences);
547548
};
@@ -610,41 +611,25 @@ namespace ts {
610611
return system === sys && (compilerOptions.diagnostics || compilerOptions.extendedDiagnostics);
611612
}
612613

613-
let traceCount = 0;
614-
let tracingFd: number | undefined;
614+
function canTrace(system: System, compilerOptions: CompilerOptions) {
615+
return system === sys && compilerOptions.generateTrace;
616+
}
615617

616-
function enableStatisticsAndTracing(system: System, compilerOptions: CompilerOptions) {
618+
function enableStatisticsAndTracing(system: System, compilerOptions: CompilerOptions, isBuildMode: boolean) {
617619
if (canReportDiagnostics(system, compilerOptions)) {
618620
performance.enable();
619621
}
620622

621-
Debug.assert(!tracingFd, "Tracing already started");
622-
if (system === sys) {
623-
const tracePath = compilerOptions.generateTrace;
624-
if (tracePath) {
625-
const extension = getAnyExtensionFromPath(tracePath);
626-
tracingFd = sys.openFile(changeAnyExtension(tracePath, `${++traceCount}${extension}`), "w");
627-
if (tracingFd) {
628-
tracing.startTracing(event => sys.write(event, tracingFd));
629-
}
630-
}
623+
if (canTrace(system, compilerOptions)) {
624+
tracing.startTracing(compilerOptions.configFilePath, compilerOptions.generateTrace!, isBuildMode);
631625
}
632626
}
633627

634628
function reportStatistics(sys: System, program: Program) {
635629
const compilerOptions = program.getCompilerOptions();
636630

637-
if (tracingFd) {
638-
tracing.stopTracing();
639-
sys.closeFile(tracingFd);
640-
tracingFd = undefined;
641-
642-
const typesPath = changeAnyExtension(compilerOptions.generateTrace!, `${traceCount}.types.json`);
643-
const typesFd = sys.openFile(typesPath, "w");
644-
if (typesFd) {
645-
tracing.dumpTypes(program.getTypeCatalog(), type => sys.write(type, typesFd));
646-
sys.closeFile(typesFd);
647-
}
631+
if (canTrace(sys, compilerOptions)) {
632+
tracing.stopTracing(program.getTypeCatalog());
648633
}
649634

650635
let statistics: Statistic[];

src/harness/fakesHosts.ts

+1-11
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ namespace fakes {
3737
return true;
3838
}
3939

40-
public write(message: string, fd?: number) {
41-
assert.isUndefined(fd);
40+
public write(message: string) {
4241
this.output.push(message);
4342
}
4443

@@ -61,15 +60,6 @@ namespace fakes {
6160
this.vfs.unlinkSync(path);
6261
}
6362

64-
public openFile(_path: string, _mode: "w"): number | undefined {
65-
assert.fail("NYI");
66-
return undefined;
67-
}
68-
69-
public closeFile(_fd: number): void{
70-
assert.fail("NYI");
71-
}
72-
7363
public fileExists(path: string) {
7464
const stats = this._getStats(path);
7565
return stats ? stats.isFile() : false;

src/harness/harnessLanguageService.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -724,8 +724,7 @@ namespace Harness.LanguageService {
724724

725725
onMessage = ts.noop;
726726
writeMessage = ts.noop; // overridden
727-
write(message: string, fd?: number): void {
728-
assert.isUndefined(fd);
727+
write(message: string): void {
729728
this.writeMessage(message);
730729
}
731730

@@ -745,9 +744,6 @@ namespace Harness.LanguageService {
745744

746745
writeFile = ts.noop;
747746

748-
openFile = ts.returnUndefined;
749-
closeFile = ts.noop;
750-
751747
resolvePath(path: string): string {
752748
return path;
753749
}

src/harness/virtualFileSystemWithWatch.ts

+1-11
Original file line numberDiff line numberDiff line change
@@ -1011,21 +1011,11 @@ interface Array<T> { length: number; [n: number]: T; }`
10111011
}
10121012
}
10131013

1014-
openFile(_path: string, _mode: "w"): number | undefined {
1015-
assert.fail("NYI");
1016-
return undefined;
1017-
}
1018-
1019-
closeFile(_fd: number): void {
1020-
assert.fail("NYI");
1021-
}
1022-
10231014
appendFile(path: string, content: string, options?: Partial<ReloadWatchInvokeOptions>): void {
10241015
this.modifyFile(path, this.readFile(path) + content, options);
10251016
}
10261017

1027-
write(message: string, fd?: number) {
1028-
assert.isUndefined(fd);
1018+
write(message: string) {
10291019
this.output.push(message);
10301020
}
10311021

0 commit comments

Comments
 (0)