@@ -35,7 +35,6 @@ import type { IPhase } from '../../api/CommandLineConfiguration';
35
35
import type { BuildCacheConfiguration } from '../../api/BuildCacheConfiguration' ;
36
36
import type { IOperationExecutionResult } from './IOperationExecutionResult' ;
37
37
import type { OperationExecutionRecord } from './OperationExecutionRecord' ;
38
- import type { IInputsSnapshot } from '../incremental/InputsSnapshot' ;
39
38
40
39
const PLUGIN_NAME : 'CacheablePhasedOperationPlugin' = 'CacheablePhasedOperationPlugin' ;
41
40
const PERIODIC_CALLBACK_INTERVAL_IN_SECONDS : number = 10 ;
@@ -88,8 +87,6 @@ export class CacheableOperationPlugin implements IPhasedCommandPlugin {
88
87
public apply ( hooks : PhasedCommandHooks ) : void {
89
88
const { allowWarningsInSuccessfulBuild, buildCacheConfiguration, cobuildConfiguration } = this . _options ;
90
89
91
- const { cacheHashSalt } = buildCacheConfiguration ;
92
-
93
90
hooks . beforeExecuteOperations . tap (
94
91
PLUGIN_NAME ,
95
92
(
@@ -104,76 +101,15 @@ export class CacheableOperationPlugin implements IPhasedCommandPlugin {
104
101
) ;
105
102
}
106
103
107
- // This redefinition is necessary due to limitations in TypeScript's control flow analysis, due to the nested closure.
108
- const definitelyDefinedInputsSnapshot : IInputsSnapshot = inputsSnapshot ;
109
-
110
104
const disjointSet : DisjointSet < Operation > | undefined = cobuildConfiguration ?. cobuildFeatureEnabled
111
105
? new DisjointSet ( )
112
106
: undefined ;
113
107
114
- const hashByOperation : Map < Operation , string > = new Map ( ) ;
115
- // Build cache hashes are computed up front to ensure stability and to catch configuration errors early.
116
- function getOrCreateOperationHash ( operation : Operation ) : string {
117
- const cachedHash : string | undefined = hashByOperation . get ( operation ) ;
118
- if ( cachedHash !== undefined ) {
119
- return cachedHash ;
120
- }
121
-
122
- // Examples of data in the config hash:
123
- // - CLI parameters (ShellOperationRunner)
124
- const configHash : string | undefined = operation . runner ?. getConfigHash ( ) ;
125
-
126
- const { associatedProject, associatedPhase } = operation ;
127
- // Examples of data in the local state hash:
128
- // - Environment variables specified in `dependsOnEnvVars`
129
- // - Git hashes of tracked files in the associated project
130
- // - Git hash of the shrinkwrap file for the project
131
- // - Git hashes of any files specified in `dependsOnAdditionalFiles` (must not be associated with a project)
132
- const localStateHash : string | undefined =
133
- associatedProject &&
134
- definitelyDefinedInputsSnapshot . getOperationOwnStateHash (
135
- associatedProject ,
136
- associatedPhase ?. name
137
- ) ;
138
-
139
- // The final state hashes of operation dependencies are factored into the hash to ensure that any
140
- // state changes in dependencies will invalidate the cache.
141
- const dependencyHashes : string [ ] = Array . from ( operation . dependencies , getDependencyHash ) . sort ( ) ;
142
-
143
- const hasher : crypto . Hash = crypto . createHash ( 'sha1' ) ;
144
- // This property is used to force cache bust when version changes, e.g. when fixing bugs in the content
145
- // of the build cache.
146
- hasher . update ( `${ RushConstants . buildCacheVersion } ` ) ;
147
-
148
- if ( cacheHashSalt !== undefined ) {
149
- // This allows repository owners to force a cache bust by changing the salt.
150
- // A common use case is to invalidate the cache when adding/removing/updating rush plugins that alter the build output.
151
- hasher . update ( cacheHashSalt ) ;
152
- }
153
-
154
- for ( const dependencyHash of dependencyHashes ) {
155
- hasher . update ( dependencyHash ) ;
156
- }
157
-
158
- if ( localStateHash ) {
159
- hasher . update ( `${ RushConstants . hashDelimiter } ${ localStateHash } ` ) ;
160
- }
161
-
162
- if ( configHash ) {
163
- hasher . update ( `${ RushConstants . hashDelimiter } ${ configHash } ` ) ;
164
- }
165
-
166
- const hashString : string = hasher . digest ( 'hex' ) ;
167
-
168
- hashByOperation . set ( operation , hashString ) ;
169
- return hashString ;
170
- }
171
-
172
- function getDependencyHash ( operation : Operation ) : string {
173
- return `${ RushConstants . hashDelimiter } ${ operation . name } =${ getOrCreateOperationHash ( operation ) } ` ;
174
- }
175
-
176
108
for ( const [ operation , record ] of recordByOperation ) {
109
+ const stateHash : string = ( record as OperationExecutionRecord ) . calculateStateHash ( {
110
+ inputsSnapshot,
111
+ buildCacheConfiguration
112
+ } ) ;
177
113
const { associatedProject, associatedPhase, runner, settings : operationSettings } = operation ;
178
114
if ( ! associatedProject || ! associatedPhase || ! runner ) {
179
115
return ;
@@ -188,7 +124,6 @@ export class CacheableOperationPlugin implements IPhasedCommandPlugin {
188
124
// depending on the selected phase.
189
125
const fileHashes : ReadonlyMap < string , string > | undefined =
190
126
inputsSnapshot . getTrackedFileHashesForOperation ( associatedProject , phaseName ) ;
191
- const stateHash : string = getOrCreateOperationHash ( operation ) ;
192
127
193
128
const cacheDisabledReason : string | undefined = projectConfiguration
194
129
? projectConfiguration . getCacheDisabledReason ( fileHashes . keys ( ) , phaseName , operation . isNoOp )
@@ -325,10 +260,8 @@ export class CacheableOperationPlugin implements IPhasedCommandPlugin {
325
260
let projectBuildCache : ProjectBuildCache | undefined = this . _tryGetProjectBuildCache ( {
326
261
buildCacheContext,
327
262
buildCacheConfiguration,
328
- rushProject : project ,
329
- phase,
330
263
terminal : buildCacheTerminal ,
331
- operation : operation
264
+ record
332
265
} ) ;
333
266
334
267
// Try to acquire the cobuild lock
@@ -639,39 +572,30 @@ export class CacheableOperationPlugin implements IPhasedCommandPlugin {
639
572
private _tryGetProjectBuildCache ( {
640
573
buildCacheConfiguration,
641
574
buildCacheContext,
642
- rushProject,
643
- phase,
644
575
terminal,
645
- operation
576
+ record
646
577
} : {
647
578
buildCacheContext : IOperationBuildCacheContext ;
648
579
buildCacheConfiguration : BuildCacheConfiguration | undefined ;
649
- rushProject : RushConfigurationProject ;
650
- phase : IPhase ;
651
580
terminal : ITerminal ;
652
- operation : Operation ;
581
+ record : OperationExecutionRecord ;
653
582
} ) : ProjectBuildCache | undefined {
654
583
if ( ! buildCacheContext . operationBuildCache ) {
655
584
const { cacheDisabledReason } = buildCacheContext ;
656
- if ( cacheDisabledReason && ! operation . settings ?. allowCobuildWithoutCache ) {
585
+ if ( cacheDisabledReason && ! record . operation . settings ?. allowCobuildWithoutCache ) {
657
586
terminal . writeVerboseLine ( cacheDisabledReason ) ;
658
587
return ;
659
588
}
660
589
661
- const { outputFolderNames, stateHash : operationStateHash } = buildCacheContext ;
662
- if ( ! outputFolderNames || ! buildCacheConfiguration ) {
590
+ if ( ! buildCacheConfiguration ) {
663
591
// Unreachable, since this will have set `cacheDisabledReason`.
664
592
return ;
665
593
}
666
594
667
595
// eslint-disable-next-line require-atomic-updates -- This is guaranteed to not be concurrent
668
- buildCacheContext . operationBuildCache = ProjectBuildCache . getProjectBuildCache ( {
669
- project : rushProject ,
670
- projectOutputFolderNames : outputFolderNames ,
596
+ buildCacheContext . operationBuildCache = ProjectBuildCache . forOperation ( record , {
671
597
buildCacheConfiguration,
672
- terminal,
673
- operationStateHash,
674
- phaseName : phase . name
598
+ terminal
675
599
} ) ;
676
600
}
677
601
0 commit comments