@@ -38,56 +38,37 @@ public function __construct(string $rootDir, IOInterface $io)
3838 */
3939 public function applyPatch (RecipePatch $ patch ): bool
4040 {
41- if (!$ patch ->getPatch ()) {
42- // nothing to do!
43- return true ;
44- }
45-
46- $ addedBlobs = $ this ->addMissingBlobs ($ patch ->getBlobs ());
47-
48- $ patchPath = $ this ->rootDir .'/_flex_recipe_update.patch ' ;
49- file_put_contents ($ patchPath , $ patch ->getPatch ());
50-
51- try {
52- $ this ->execute ('git update-index --refresh ' , $ this ->rootDir );
53-
54- $ output = '' ;
55- $ statusCode = $ this ->processExecutor ->execute ('git apply "_flex_recipe_update.patch" -3 ' , $ output , $ this ->rootDir );
41+ $ withConflicts = $ this ->_applyPatchFile ($ patch );
5642
57- if (0 === $ statusCode ) {
58- // successful with no conflicts
59- return true ;
60- }
61-
62- if (false !== strpos ($ this ->processExecutor ->getErrorOutput (), 'with conflicts ' )) {
63- // successful with conflicts
64- return false ;
65- }
66-
67- throw new \LogicException ('Error applying the patch: ' .$ this ->processExecutor ->getErrorOutput ());
68- } finally {
69- unlink ($ patchPath );
70- // clean up any temporary blobs
71- foreach ($ addedBlobs as $ filename ) {
72- unlink ($ filename );
43+ foreach ($ patch ->getDeletedFiles () as $ deletedFile ) {
44+ if (file_exists ($ this ->rootDir .'/ ' .$ deletedFile )) {
45+ $ this ->execute (sprintf ('git rm %s ' , ProcessExecutor::escape ($ deletedFile )), $ this ->rootDir );
7346 }
7447 }
48+
49+ return $ withConflicts ;
7550 }
7651
7752 public function generatePatch (array $ originalFiles , array $ newFiles ): RecipePatch
7853 {
54+ $ ignoredFiles = $ this ->getIgnoredFiles (array_keys ($ originalFiles ) + array_keys ($ newFiles ));
55+
7956 // null implies "file does not exist"
80- $ originalFiles = array_filter ($ originalFiles , function ($ file ) {
81- return null !== $ file ;
82- });
83- $ newFiles = array_filter ($ newFiles , function ($ file ) {
84- return null !== $ file ;
85- });
86-
87- // find removed files and add them so they will be deleted
57+ $ originalFiles = array_filter ($ originalFiles , function ($ file , $ fileName ) use ($ ignoredFiles ) {
58+ return null !== $ file && !\in_array ($ fileName , $ ignoredFiles );
59+ }, \ARRAY_FILTER_USE_BOTH );
60+
61+ $ newFiles = array_filter ($ newFiles , function ($ file , $ fileName ) use ($ ignoredFiles ) {
62+ return null !== $ file && !\in_array ($ fileName , $ ignoredFiles );
63+ }, \ARRAY_FILTER_USE_BOTH );
64+
65+ $ deletedFiles = [];
66+ // find removed files & record that they are deleted
67+ // unset them from originalFiles to avoid unnecessary blobs being added
8868 foreach ($ originalFiles as $ file => $ contents ) {
8969 if (!isset ($ newFiles [$ file ])) {
90- $ newFiles [$ file ] = null ;
70+ $ deletedFiles [] = $ file ;
71+ unset($ originalFiles [$ file ]);
9172 }
9273 }
9374
@@ -130,6 +111,7 @@ public function generatePatch(array $originalFiles, array $newFiles): RecipePatc
130111 return new RecipePatch (
131112 $ patchString ,
132113 $ blobs ,
114+ $ deletedFiles ,
133115 $ removedPatches
134116 );
135117 } finally {
@@ -223,4 +205,51 @@ private function getBlobPath(string $hash): string
223205
224206 return '.git/objects/ ' .$ hashStart .'/ ' .$ hashEnd ;
225207 }
208+
209+ private function _applyPatchFile (RecipePatch $ patch )
210+ {
211+ if (!$ patch ->getPatch ()) {
212+ // nothing to do!
213+ return true ;
214+ }
215+
216+ $ addedBlobs = $ this ->addMissingBlobs ($ patch ->getBlobs ());
217+
218+ $ patchPath = $ this ->rootDir .'/_flex_recipe_update.patch ' ;
219+ file_put_contents ($ patchPath , $ patch ->getPatch ());
220+
221+ try {
222+ $ this ->execute ('git update-index --refresh ' , $ this ->rootDir );
223+
224+ $ output = '' ;
225+ $ statusCode = $ this ->processExecutor ->execute ('git apply "_flex_recipe_update.patch" -3 ' , $ output , $ this ->rootDir );
226+
227+ if (0 === $ statusCode ) {
228+ // successful with no conflicts
229+ return true ;
230+ }
231+
232+ if (false !== strpos ($ this ->processExecutor ->getErrorOutput (), 'with conflicts ' )) {
233+ // successful with conflicts
234+ return false ;
235+ }
236+
237+ throw new \LogicException ('Error applying the patch: ' .$ this ->processExecutor ->getErrorOutput ());
238+ } finally {
239+ unlink ($ patchPath );
240+ // clean up any temporary blobs
241+ foreach ($ addedBlobs as $ filename ) {
242+ unlink ($ filename );
243+ }
244+ }
245+ }
246+
247+ private function getIgnoredFiles (array $ fileNames ): array
248+ {
249+ $ args = implode (' ' , array_map ([ProcessExecutor::class, 'escape ' ], $ fileNames ));
250+ $ output = '' ;
251+ $ this ->processExecutor ->execute (sprintf ('git check-ignore %s ' , $ args ), $ output , $ this ->rootDir );
252+
253+ return $ this ->processExecutor ->splitLines ($ output );
254+ }
226255}
0 commit comments