@@ -13,7 +13,6 @@ import { join, relative, resolve } from "./path"
13
13
import {
14
14
clearPatchApplicationState ,
15
15
getPatchApplicationState ,
16
- PatchState ,
17
16
savePatchApplicationState ,
18
17
} from "./stateFile"
19
18
@@ -118,8 +117,8 @@ export function applyPatchesForApp({
118
117
) ) {
119
118
const state =
120
119
patches . length > 1 ? getPatchApplicationState ( patches [ 0 ] ) : null
121
- let unappliedPatches = patches . slice ( 0 )
122
- const newState : PatchState [ ] | null = patches . length > 1 ? [ ] : null
120
+ const unappliedPatches = patches . slice ( 0 )
121
+ const appliedPatches : PatchedPackageDetails [ ] = [ ]
123
122
// if there are multiple patches to apply, we can't rely on the reverse-patch-dry-run behavior to make this operation
124
123
// idempotent, so instead we need to check the state file to see whether we have already applied any of the patches
125
124
// todo: once this is battle tested we might want to use the same approach for single patches as well, but it's not biggie since the dry run thing is fast
@@ -132,7 +131,7 @@ export function applyPatchesForApp({
132
131
)
133
132
if ( patchThatWasApplied . patchContentHash === currentPatchHash ) {
134
133
// this patch was applied we can skip it
135
- unappliedPatches . shift ( )
134
+ appliedPatches . push ( unappliedPatches . shift ( ) ! )
136
135
} else {
137
136
console . error (
138
137
chalk . red ( "Error:" ) ,
@@ -144,14 +143,21 @@ export function applyPatchesForApp({
144
143
}
145
144
}
146
145
147
- if ( reverse ) {
148
- unappliedPatches = patches
149
- . slice ( 0 , patches . length - unappliedPatches . length )
150
- . reverse ( )
146
+ if ( reverse && state ) {
147
+ // if we are reversing the patches we need to make the unappliedPatches array
148
+ // be the reversed version of the appliedPatches array.
149
+ // The applied patches array should then be empty because it is used differently
150
+ // when outputting the state file.
151
+ unappliedPatches . length = 0
152
+ unappliedPatches . push ( ...appliedPatches )
153
+ unappliedPatches . reverse ( )
154
+ appliedPatches . length = 0
151
155
}
152
- if ( unappliedPatches . length === 0 ) {
156
+ if ( appliedPatches . length ) {
153
157
// all patches have already been applied
154
- patches . forEach ( logPatchApplication )
158
+ appliedPatches . forEach ( logPatchApplication )
159
+ }
160
+ if ( ! unappliedPatches . length ) {
155
161
continue
156
162
}
157
163
packageLoop: for ( const patchDetails of unappliedPatches ) {
@@ -191,11 +197,7 @@ export function applyPatchesForApp({
191
197
cwd : process . cwd ( ) ,
192
198
} )
193
199
) {
194
- newState ?. push ( {
195
- patchFilename,
196
- patchContentHash : hashFile ( join ( appPath , patchDir , patchFilename ) ) ,
197
- didApply : true ,
198
- } )
200
+ appliedPatches . push ( patchDetails )
199
201
// yay patch was applied successfully
200
202
// print warning if version mismatch
201
203
if ( installedPackageVersion !== version ) {
@@ -256,11 +258,53 @@ export function applyPatchesForApp({
256
258
}
257
259
}
258
260
259
- if ( newState ) {
261
+ if ( patches . length > 1 ) {
260
262
if ( reverse ) {
261
- clearPatchApplicationState ( patches [ 0 ] )
263
+ if ( ! state ) {
264
+ throw new Error (
265
+ "unexpected state: no state file found while reversing" ,
266
+ )
267
+ }
268
+ // if we removed all the patches that were previously applied we can delete the state file
269
+ if ( appliedPatches . length === patches . length ) {
270
+ clearPatchApplicationState ( patches [ 0 ] )
271
+ } else {
272
+ // We failed while reversing patches and some are still in the applied state.
273
+ // We need to update the state file to reflect that.
274
+ // appliedPatches is currently the patches that were successfully reversed, in the order they were reversed
275
+ // So we need to find the index of the last reversed patch in the original patches array
276
+ // and then remove all the patches after that. Sorry for the confusing code.
277
+ const lastReversedPatchIndex = patches . indexOf (
278
+ appliedPatches [ appliedPatches . length - 1 ] ,
279
+ )
280
+ if ( lastReversedPatchIndex === - 1 ) {
281
+ throw new Error (
282
+ "unexpected state: failed to find last reversed patch in original patches array" ,
283
+ )
284
+ }
285
+
286
+ savePatchApplicationState (
287
+ patches [ 0 ] ,
288
+ patches . slice ( 0 , lastReversedPatchIndex ) . map ( ( patch ) => ( {
289
+ didApply : true ,
290
+ patchContentHash : hashFile (
291
+ join ( appPath , patchDir , patch . patchFilename ) ,
292
+ ) ,
293
+ patchFilename : patch . patchFilename ,
294
+ } ) ) ,
295
+ )
296
+ }
262
297
} else {
263
- savePatchApplicationState ( patches [ 0 ] , newState )
298
+ savePatchApplicationState (
299
+ patches [ 0 ] ,
300
+ appliedPatches . map ( ( patch ) => ( {
301
+ didApply : true ,
302
+ patchContentHash : hashFile (
303
+ join ( appPath , patchDir , patch . patchFilename ) ,
304
+ ) ,
305
+ patchFilename : patch . patchFilename ,
306
+ } ) ) ,
307
+ )
264
308
}
265
309
}
266
310
}
0 commit comments