Skip to content

Commit 863a2a0

Browse files
committed
Adding option to write patches for files deleted in user's app
1 parent 2cd5441 commit 863a2a0

File tree

6 files changed

+425
-7
lines changed

6 files changed

+425
-7
lines changed

src/Command/UpdateRecipesCommand.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,33 @@ protected function execute(InputInterface $input, OutputInterface $output): int
197197
]);
198198
}
199199

200+
if (0 !== \count($patch->getRemovedPatches())) {
201+
if (1 === \count($patch->getRemovedPatches())) {
202+
$notes = [
203+
sprintf(' The file <comment>%s</comment> was not updated because it doesn\'t exist in your app.', array_keys($patch->getRemovedPatches())[0]),
204+
];
205+
} else {
206+
$notes = [' The following files were not updated because they don\'t exist in your app:'];
207+
foreach ($patch->getRemovedPatches() as $filename => $contents) {
208+
$notes[] = sprintf(' * <comment>%s</comment>', $filename);
209+
}
210+
}
211+
$io->write([
212+
'',
213+
' <bg=red;fg=white>NOTE:</>',
214+
]);
215+
$io->write($notes);
216+
$io->write('');
217+
if ($io->askConfirmation(' Would you like to save the "diff" to a file so you can review it? (Y/n) ')) {
218+
$patchFilename = str_replace('/', '.', $packageName).'.updates-for-deleted-files.patch';
219+
file_put_contents($this->rootDir.'/'.$patchFilename, implode("\n", $patch->getRemovedPatches()));
220+
$io->write([
221+
'',
222+
sprintf(' Saved diff to <info>%s</info>', $patchFilename),
223+
]);
224+
}
225+
}
226+
200227
if ($patch->getPatch()) {
201228
$io->write('');
202229
$io->write(' Calculating CHANGELOG...', false);

src/Update/DiffHelper.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Flex\Update;
13+
14+
class DiffHelper
15+
{
16+
public static function removeFilesFromPatch(string $patch, array $files, array &$removedPatches): string
17+
{
18+
foreach ($files as $filename) {
19+
$start = strpos($patch, sprintf('diff --git a/%s b/%s', $filename, $filename));
20+
if (false === $start) {
21+
throw new \LogicException(sprintf('Could not find file "%s" in the patch', $filename));
22+
}
23+
24+
$end = strpos($patch, 'diff --git a/', $start + 1);
25+
$contentBefore = substr($patch, 0, $start);
26+
if (false === $end) {
27+
// last patch in the file
28+
$removedPatches[$filename] = rtrim(substr($patch, $start), "\n");
29+
$patch = rtrim($contentBefore, "\n");
30+
31+
continue;
32+
}
33+
34+
$removedPatches[$filename] = rtrim(substr($patch, $start, $end - $start), "\n");
35+
$patch = $contentBefore.substr($patch, $end);
36+
}
37+
38+
return $patch;
39+
}
40+
}

src/Update/RecipePatch.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ class RecipePatch
1515
{
1616
private $patch;
1717
private $blobs;
18+
private $removedPatches;
1819

19-
public function __construct(string $patch, array $blobs)
20+
public function __construct(string $patch, array $blobs, array $removedPatches = [])
2021
{
2122
$this->patch = $patch;
2223
$this->blobs = $blobs;
24+
$this->removedPatches = $removedPatches;
2325
}
2426

2527
public function getPatch(): string
@@ -31,4 +33,13 @@ public function getBlobs(): array
3133
{
3234
return $this->blobs;
3335
}
36+
37+
/**
38+
* Patches for modified files that were removed because the file
39+
* has been deleted in the user's project.
40+
*/
41+
public function getRemovedPatches(): array
42+
{
43+
return $this->removedPatches;
44+
}
3445
}

src/Update/RecipePatcher.php

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,13 @@ public function generatePatch(array $originalFiles, array $newFiles): RecipePatc
9393
}
9494

9595
// If a file is being modified, but does not exist in the current project,
96-
// it cannot be patched. Ignore these files and leave them deleted.
96+
// it cannot be patched. We generate the diff for these, but then remove
97+
// it from the patch (and optionally report this diff to the user).
9798
$modifiedFiles = array_intersect_key(array_keys($originalFiles), array_keys($newFiles));
99+
$deletedModifiedFiles = [];
98100
foreach ($modifiedFiles as $modifiedFile) {
99101
if (!file_exists($this->rootDir.'/'.$modifiedFile)) {
100-
unset($originalFiles[$modifiedFile]);
101-
unset($newFiles[$modifiedFile]);
102+
$deletedModifiedFiles[] = $modifiedFile;
102103
}
103104
}
104105

@@ -122,9 +123,14 @@ public function generatePatch(array $originalFiles, array $newFiles): RecipePatc
122123
$this->writeFiles($newFiles, $tmpPath);
123124
$this->execute('git add -A', $tmpPath);
124125

126+
$patchString = $this->execute('git diff --cached', $tmpPath);
127+
$removedPatches = [];
128+
$patchString = DiffHelper::removeFilesFromPatch($patchString, $deletedModifiedFiles, $removedPatches);
129+
125130
return new RecipePatch(
126-
$this->execute('git diff --cached', $tmpPath),
127-
$blobs
131+
$patchString,
132+
$blobs,
133+
$removedPatches
128134
);
129135
} finally {
130136
try {

0 commit comments

Comments
 (0)