Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deduplicate patch collection as patches are added #496

Merged
merged 2 commits into from
Feb 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/usage/defining-patches.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ If you're defining patches in `patches.json` (or some other separate patches fil
}
```

## Duplicate patches

If the same patch is defined in multiple places, the first one added to the patch collection "wins". Subsequent definitions of the same patch will be ignored without emitting an error. The criteria used for determining whether two patches are the same are:

* They have the same URL
* They have the same sha256 hash

## `patches.lock.json`

If `patches.lock.json` does not exist the first time you run `composer install` with this plugin enabled, one will be created for you. Generally, you shouldn't need to do anything with this file: commit it to your project repository alongside your `composer.json` and `composer.lock`, and commit any changes when you change your patch definitions.
Expand Down
16 changes: 16 additions & 0 deletions src/PatchCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ class PatchCollection implements JsonSerializable
*/
public function addPatch(Patch $patch)
{
if (array_key_exists($patch->package, $this->patches)) {
foreach ($this->patches[$patch->package] as $existing_patch) {
$has_same_url = ($patch->url === $existing_patch->url);
$has_same_sha = (
isset($patch->sha256) &&
isset($existing_patch->sha256) &&
($patch->sha256 === $existing_patch->sha256)
);

if ($has_same_url || $has_same_sha) {
// If we already have the patch, don't try to add it again.
return;
}
}
}

$this->patches[$patch->package][] = $patch;
}

Expand Down
6 changes: 3 additions & 3 deletions tests/_data/dummyPatches.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@
"description": "Test patch"
},
{
"url": "https://drupal.org",
"url": "https://drupal.org/foo",
"description": "Test patch"
}
],
"test/package2": [
{
"url": "https://drupal.org",
"url": "https://drupal.org/bar",
"description": "Test patch"
},
{
"url": "https://drupal.org",
"url": "https://drupal.org/baz",
"description": "Test patch"
}
]
Expand Down
45 changes: 44 additions & 1 deletion tests/unit/PatchCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,25 @@ public function testPatchCollectionAddRetrieve()
$patch1 = new Patch();
$patch1->package = 'some/package';
$patch1->description = 'patch1';
$patch1->url = '1';
$collection->addPatch($patch1);

$patch2 = new Patch();
$patch2->package = 'some/package';
$patch2->description = 'patch2';
$patch2->url = '2';
$collection->addPatch($patch2);

$patch3 = new Patch();
$patch3->package = 'other/package';
$patch3->description = 'patch3';
$patch3->url = '3';
$collection->addPatch($patch3);

$patch4 = new Patch();
$patch4->package = 'other/package';
$patch4->description = 'patch4';
$patch4->url = '4';
$collection->addPatch($patch4);

foreach (['some/package', 'other/package'] as $package_name) {
Expand Down Expand Up @@ -64,6 +68,45 @@ public function testPatchCollectionAddRetrieve()
$this->assertContains('some/package', $packages);
}

public function testPatchDeduplication()
{
$collection = new PatchCollection();

// First, make sure that we don't get anything out of an empty collection.
$this->assertEmpty($collection->getPatchesForPackage('some/package'));

// Add two patches with the same URL.
$patch1 = new Patch();
$patch1->package = 'some/package';
$patch1->description = 'patch1';
$patch1->url = 'https://example.com';
$collection->addPatch($patch1);

$patch2 = new Patch();
$patch2->package = 'some/package';
$patch2->description = 'patch2';
$patch2->url = 'https://example.com';
$collection->addPatch($patch2);

// We should only have one patch now.
$this->assertCount(1, $collection->getPatchedPackages('some/package'));
$this->assertEquals('patch1', $collection->getPatchesForPackage('some/package')[0]->description);

// Start over to test deduplication with sha256.
$collection = new PatchCollection();
$this->assertEmpty($collection->getPatchesForPackage('some/package'));

$patch1->sha256 = 'asdf';
$patch2->sha256 = 'asdf';
$patch2->url = 'https://example.com#something-different';

$collection->addPatch($patch1);
$collection->addPatch($patch2);

$this->assertCount(1, $collection->getPatchedPackages('some/package'));
$this->assertEquals('patch1', $collection->getPatchesForPackage('some/package')[0]->description);
}

public function testSerializeDeserialize()
{
$collection = new PatchCollection();
Expand All @@ -77,7 +120,7 @@ public function testSerializeDeserialize()
$patch2 = new Patch();
$patch2->package = 'another/package';
$patch2->description = 'patch2';
$patch2->url = 'https://example.com/test.patch';
$patch2->url = 'https://example.com/test2.patch';
$patch2->extra = [];

$collection->addPatch($patch1);
Expand Down