From a0dcb765bc54dfdebb25666eab37c5e46cc589bb Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Tue, 13 Apr 2021 17:26:45 -0700 Subject: [PATCH 1/4] Skip up-to-date checks during force build Save work by not checking timestamps or parsing the buildinfo file. Retain correctness checks (like input file existence). Suppress project status, which was confusing anyway. --- src/compiler/tsbuildPublic.ts | 93 ++++++++++--------- ...uilds-from-start-if-force-option-is-set.js | 6 -- 2 files changed, 50 insertions(+), 49 deletions(-) diff --git a/src/compiler/tsbuildPublic.ts b/src/compiler/tsbuildPublic.ts index d642f79a12447..28dd770c3c477 100644 --- a/src/compiler/tsbuildPublic.ts +++ b/src/compiler/tsbuildPublic.ts @@ -1350,6 +1350,7 @@ namespace ts { } function getUpToDateStatusWorker(state: SolutionBuilderState, project: ParsedCommandLine, resolvedPath: ResolvedConfigFilePath): UpToDateStatus { + const force = !!state.options.force; let newestInputFileName: string = undefined!; let newestInputFileTime = minimumDate; const { host } = state; @@ -1362,10 +1363,12 @@ namespace ts { }; } - const inputTime = getModifiedTime(host, inputFile); host.getModifiedTime(inputFile); - if (inputTime > newestInputFileTime) { - newestInputFileName = inputFile; - newestInputFileTime = inputTime; + if (!force) { + const inputTime = getModifiedTime(host, inputFile); host.getModifiedTime(inputFile); + if (inputTime > newestInputFileTime) { + newestInputFileName = inputFile; + newestInputFileTime = inputTime; + } } } @@ -1387,39 +1390,41 @@ namespace ts { let missingOutputFileName: string | undefined; let newestDeclarationFileContentChangedTime = minimumDate; let isOutOfDateWithInputs = false; - for (const output of outputs) { - // Output is missing; can stop checking - // Don't immediately return because we can still be upstream-blocked, which is a higher-priority status - if (!host.fileExists(output)) { - missingOutputFileName = output; - break; - } + if (!force) { + for (const output of outputs) { + // Output is missing; can stop checking + // Don't immediately return because we can still be upstream-blocked, which is a higher-priority status + if (!host.fileExists(output)) { + missingOutputFileName = output; + break; + } - const outputTime = getModifiedTime(host, output); - if (outputTime < oldestOutputFileTime) { - oldestOutputFileTime = outputTime; - oldestOutputFileName = output; - } + const outputTime = getModifiedTime(host, output); + if (outputTime < oldestOutputFileTime) { + oldestOutputFileTime = outputTime; + oldestOutputFileName = output; + } - // If an output is older than the newest input, we can stop checking - // Don't immediately return because we can still be upstream-blocked, which is a higher-priority status - if (outputTime < newestInputFileTime) { - isOutOfDateWithInputs = true; - break; - } + // If an output is older than the newest input, we can stop checking + // Don't immediately return because we can still be upstream-blocked, which is a higher-priority status + if (outputTime < newestInputFileTime) { + isOutOfDateWithInputs = true; + break; + } - if (outputTime > newestOutputFileTime) { - newestOutputFileTime = outputTime; - newestOutputFileName = output; - } + if (outputTime > newestOutputFileTime) { + newestOutputFileTime = outputTime; + newestOutputFileName = output; + } - // Keep track of when the most recent time a .d.ts file was changed. - // In addition to file timestamps, we also keep track of when a .d.ts file - // had its file touched but not had its contents changed - this allows us - // to skip a downstream typecheck - if (isDeclarationFile(output)) { - const outputModifiedTime = getModifiedTime(host, output); - newestDeclarationFileContentChangedTime = newer(newestDeclarationFileContentChangedTime, outputModifiedTime); + // Keep track of when the most recent time a .d.ts file was changed. + // In addition to file timestamps, we also keep track of when a .d.ts file + // had its file touched but not had its contents changed - this allows us + // to skip a downstream typecheck + if (isDeclarationFile(output)) { + const outputModifiedTime = getModifiedTime(host, output); + newestDeclarationFileContentChangedTime = newer(newestDeclarationFileContentChangedTime, outputModifiedTime); + } } } @@ -1511,15 +1516,17 @@ namespace ts { if (!state.buildInfoChecked.has(resolvedPath)) { state.buildInfoChecked.set(resolvedPath, true); - const buildInfoPath = getTsBuildInfoEmitOutputFilePath(project.options); - if (buildInfoPath) { - const value = state.readFileWithCache(buildInfoPath); - const buildInfo = value && getBuildInfo(value); - if (buildInfo && (buildInfo.bundle || buildInfo.program) && buildInfo.version !== version) { - return { - type: UpToDateStatusType.TsVersionOutputOfDate, - version: buildInfo.version - }; + if (!force) { + const buildInfoPath = getTsBuildInfoEmitOutputFilePath(project.options); + if (buildInfoPath) { + const value = state.readFileWithCache(buildInfoPath); + const buildInfo = value && getBuildInfo(value); + if (buildInfo && (buildInfo.bundle || buildInfo.program) && buildInfo.version !== version) { + return { + type: UpToDateStatusType.TsVersionOutputOfDate, + version: buildInfo.version + }; + } } } } @@ -2100,7 +2107,7 @@ namespace ts { * Report the up-to-date status of a project if we're in verbose mode */ function verboseReportProjectStatus(state: SolutionBuilderState, configFileName: string, status: UpToDateStatus) { - if (state.options.verbose) { + if (state.options.verbose && !state.options.force) { reportUpToDateStatus(state, configFileName, status); } } diff --git a/tests/baselines/reference/tsbuild/sample1/incremental-declaration-changes/rebuilds-from-start-if-force-option-is-set.js b/tests/baselines/reference/tsbuild/sample1/incremental-declaration-changes/rebuilds-from-start-if-force-option-is-set.js index 383079f263d41..6f24d01a98579 100644 --- a/tests/baselines/reference/tsbuild/sample1/incremental-declaration-changes/rebuilds-from-start-if-force-option-is-set.js +++ b/tests/baselines/reference/tsbuild/sample1/incremental-declaration-changes/rebuilds-from-start-if-force-option-is-set.js @@ -8,16 +8,10 @@ Output:: * src/logic/tsconfig.json * src/tests/tsconfig.json -[12:16:00 AM] Project 'src/core/tsconfig.json' is up to date because newest input 'src/core/anotherModule.ts' is older than oldest output 'src/core/anotherModule.js' - [12:16:00 AM] Building project '/src/core/tsconfig.json'... -[12:16:00 AM] Project 'src/logic/tsconfig.json' is up to date with .d.ts files from its dependencies - [12:16:00 AM] Building project '/src/logic/tsconfig.json'... -[12:16:00 AM] Project 'src/tests/tsconfig.json' is up to date with .d.ts files from its dependencies - [12:16:00 AM] Building project '/src/tests/tsconfig.json'... exitCode:: ExitStatus.Success From d93f99a0acc8b152e26a4ffd4abe928ff25298b4 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Fri, 16 Apr 2021 10:42:47 -0700 Subject: [PATCH 2/4] Print a message to indicate that --force is causing the rebuild --- src/compiler/diagnosticMessages.json | 4 ++++ src/compiler/tsbuildPublic.ts | 10 +++++++++- .../rebuilds-from-start-if-force-option-is-set.js | 6 ++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 270c1b7da3437..9b36515d5b490 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -5041,6 +5041,10 @@ "code": 6387, "reportsDeprecated": true }, + "Project '{0}' is being forcibly rebuilt": { + "category": "Message", + "code": 6388 + }, "The expected type comes from property '{0}' which is declared here on type '{1}'": { "category": "Message", diff --git a/src/compiler/tsbuildPublic.ts b/src/compiler/tsbuildPublic.ts index 28dd770c3c477..abdf6069588ff 100644 --- a/src/compiler/tsbuildPublic.ts +++ b/src/compiler/tsbuildPublic.ts @@ -2012,6 +2012,14 @@ namespace ts { } function reportUpToDateStatus(state: SolutionBuilderState, configFileName: string, status: UpToDateStatus) { + if (state.options.force && (status.type === UpToDateStatusType.UpToDate || status.type === UpToDateStatusType.UpToDateWithUpstreamTypes)) { + return reportStatus( + state, + Diagnostics.Project_0_is_being_forcibly_rebuilt, + relName(state, configFileName) + ); + } + switch (status.type) { case UpToDateStatusType.OutOfDateWithSelf: return reportStatus( @@ -2107,7 +2115,7 @@ namespace ts { * Report the up-to-date status of a project if we're in verbose mode */ function verboseReportProjectStatus(state: SolutionBuilderState, configFileName: string, status: UpToDateStatus) { - if (state.options.verbose && !state.options.force) { + if (state.options.verbose) { reportUpToDateStatus(state, configFileName, status); } } diff --git a/tests/baselines/reference/tsbuild/sample1/incremental-declaration-changes/rebuilds-from-start-if-force-option-is-set.js b/tests/baselines/reference/tsbuild/sample1/incremental-declaration-changes/rebuilds-from-start-if-force-option-is-set.js index 6f24d01a98579..581a1fb82524c 100644 --- a/tests/baselines/reference/tsbuild/sample1/incremental-declaration-changes/rebuilds-from-start-if-force-option-is-set.js +++ b/tests/baselines/reference/tsbuild/sample1/incremental-declaration-changes/rebuilds-from-start-if-force-option-is-set.js @@ -8,10 +8,16 @@ Output:: * src/logic/tsconfig.json * src/tests/tsconfig.json +[12:16:00 AM] Project 'src/core/tsconfig.json' is being forcibly rebuilt + [12:16:00 AM] Building project '/src/core/tsconfig.json'... +[12:16:00 AM] Project 'src/logic/tsconfig.json' is being forcibly rebuilt + [12:16:00 AM] Building project '/src/logic/tsconfig.json'... +[12:16:00 AM] Project 'src/tests/tsconfig.json' is being forcibly rebuilt + [12:16:00 AM] Building project '/src/tests/tsconfig.json'... exitCode:: ExitStatus.Success From 4e39b4b8368aeac913f430f1a2cecfbee8b2e3a5 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Fri, 16 Apr 2021 15:56:39 -0700 Subject: [PATCH 3/4] Don't bother updating buildInfoChecked --- src/compiler/tsbuildPublic.ts | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/compiler/tsbuildPublic.ts b/src/compiler/tsbuildPublic.ts index abdf6069588ff..672eef3d97c4b 100644 --- a/src/compiler/tsbuildPublic.ts +++ b/src/compiler/tsbuildPublic.ts @@ -1514,19 +1514,17 @@ namespace ts { if (extendedConfigStatus) return extendedConfigStatus; } - if (!state.buildInfoChecked.has(resolvedPath)) { + if (!force && !state.buildInfoChecked.has(resolvedPath)) { state.buildInfoChecked.set(resolvedPath, true); - if (!force) { - const buildInfoPath = getTsBuildInfoEmitOutputFilePath(project.options); - if (buildInfoPath) { - const value = state.readFileWithCache(buildInfoPath); - const buildInfo = value && getBuildInfo(value); - if (buildInfo && (buildInfo.bundle || buildInfo.program) && buildInfo.version !== version) { - return { - type: UpToDateStatusType.TsVersionOutputOfDate, - version: buildInfo.version - }; - } + const buildInfoPath = getTsBuildInfoEmitOutputFilePath(project.options); + if (buildInfoPath) { + const value = state.readFileWithCache(buildInfoPath); + const buildInfo = value && getBuildInfo(value); + if (buildInfo && (buildInfo.bundle || buildInfo.program) && buildInfo.version !== version) { + return { + type: UpToDateStatusType.TsVersionOutputOfDate, + version: buildInfo.version + }; } } } From 331dfc46d7e5c301791b27652e89b63997853f0f Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Fri, 16 Apr 2021 16:37:52 -0700 Subject: [PATCH 4/4] Add missing force check --- src/compiler/tsbuildPublic.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/tsbuildPublic.ts b/src/compiler/tsbuildPublic.ts index 672eef3d97c4b..91a81eeba55c1 100644 --- a/src/compiler/tsbuildPublic.ts +++ b/src/compiler/tsbuildPublic.ts @@ -1464,7 +1464,8 @@ namespace ts { } // Check oldest output file name only if there is no missing output file name - if (!missingOutputFileName) { + // (a check we will have skipped if this is a forced build) + if (!force && !missingOutputFileName) { // If the upstream project's newest file is older than our oldest output, we // can't be out of date because of it if (refStatus.newestInputFileTime && refStatus.newestInputFileTime <= oldestOutputFileTime) {