@@ -13,7 +13,6 @@ import { join, relative, resolve } from "./path"
1313import {
1414 clearPatchApplicationState ,
1515 getPatchApplicationState ,
16- PatchState ,
1716 savePatchApplicationState ,
1817} from "./stateFile"
1918
@@ -118,8 +117,8 @@ export function applyPatchesForApp({
118117 ) ) {
119118 const state =
120119 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 [ ] = [ ]
123122 // if there are multiple patches to apply, we can't rely on the reverse-patch-dry-run behavior to make this operation
124123 // idempotent, so instead we need to check the state file to see whether we have already applied any of the patches
125124 // 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({
132131 )
133132 if ( patchThatWasApplied . patchContentHash === currentPatchHash ) {
134133 // this patch was applied we can skip it
135- unappliedPatches . shift ( )
134+ appliedPatches . push ( unappliedPatches . shift ( ) ! )
136135 } else {
137136 console . error (
138137 chalk . red ( "Error:" ) ,
@@ -144,14 +143,21 @@ export function applyPatchesForApp({
144143 }
145144 }
146145
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
151155 }
152- if ( unappliedPatches . length === 0 ) {
156+ if ( appliedPatches . length ) {
153157 // all patches have already been applied
154- patches . forEach ( logPatchApplication )
158+ appliedPatches . forEach ( logPatchApplication )
159+ }
160+ if ( ! unappliedPatches . length ) {
155161 continue
156162 }
157163 packageLoop: for ( const patchDetails of unappliedPatches ) {
@@ -191,11 +197,7 @@ export function applyPatchesForApp({
191197 cwd : process . cwd ( ) ,
192198 } )
193199 ) {
194- newState ?. push ( {
195- patchFilename,
196- patchContentHash : hashFile ( join ( appPath , patchDir , patchFilename ) ) ,
197- didApply : true ,
198- } )
200+ appliedPatches . push ( patchDetails )
199201 // yay patch was applied successfully
200202 // print warning if version mismatch
201203 if ( installedPackageVersion !== version ) {
@@ -256,11 +258,53 @@ export function applyPatchesForApp({
256258 }
257259 }
258260
259- if ( newState ) {
261+ if ( patches . length > 1 ) {
260262 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+ }
262297 } 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+ )
264308 }
265309 }
266310 }
0 commit comments