Skip to content

Commit bcb9911

Browse files
committed
Initial commit
0 parents  commit bcb9911

27 files changed

+2568
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/vendor/
2+
/composer.lock

.travis.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
language: php
2+
sudo: false
3+
dist: trusty
4+
5+
php:
6+
- 5.6
7+
- 7.0
8+
- 7.1
9+
- 7.2
10+
- 7.3
11+
- nightly
12+
13+
matrix:
14+
allow_failures:
15+
- php: nightly
16+
17+
install:
18+
- travis_retry composer install --ansi --prefer-dist --no-interaction --optimize-autoloader --no-suggest --no-progress
19+
20+
script: ./vendor/bin/phpunit

README.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
Composer Plugin For Applying Patchsets
2+
======================================
3+
4+
This plugin can automatically apply patches to any dependency of your project.
5+
6+
One of the most distinguishing features is that it can apply patches from special composer packages of type `patchset`.
7+
This is quite convenient as you can store all your patches in one repository and apply them automatically on all
8+
systems including developer's machines in a very predictable way.
9+
10+
It's (kind-of) an alternative to two other great plugins (differences will become apparent once you read __Features__):
11+
12+
* [netresearch/composer-patches-plugin](https://github.com/netresearch/composer-patches-plugin)
13+
* [cweagans/composer-patches](https://github.com/cweagans/composer-patches)
14+
15+
16+
## Features
17+
18+
- Apply patches from dedicated composer packages (package your patchset!).
19+
- Each patch can have a version constraint (composer semver) checked against the target package.
20+
21+
This means that you can (and should) have the patches fail the build if cannot be applied and still
22+
store patches for multiple package versions in the same patchset.
23+
- Apply patches using `patch` command and fall-back to `git apply` if not available.
24+
- Does not reinstall packages unnecessarily.
25+
- Reinstalls (cleans) packages which are patched but the patches have been removed guaranteeing a consistent
26+
state after multiple updates.
27+
- Will repatch packages even if **order** of patches for specific package (version) has changed.
28+
- Deduplicates patches on package level.
29+
- Does not overly tie into composer internals. All patching will be done after the main update/installation
30+
process at once execution making it simpler and easier to analyze.
31+
32+
This also means that you have the guarantee that the plugin / patches are at the latest version before
33+
the process even starts. Otherwise it's very tricky (if not impossible) to make the plugin behave
34+
consistently on the first composer install (e.g. no `vendor` dir at all) and the subsequent ones.
35+
36+
Double composer update/install for build is not necessary.
37+
38+
### What it cannot do
39+
40+
This plugin will not download patches from external sources directly (http). I consider this a bad practice and will
41+
never support it. I won't even comment on downloading patches using unencrypted connection without SHA check. Also what
42+
if somebody wants to use your software in 2 years and the patches are no longer available?
43+
44+
Also you will not be able to specify patches in any composer package. You have to use a dedicated packages for this
45+
purpose. I can hardly imagine a legit use case when it would be desirable that installing package X will automatically
46+
patch some other package Y in your project without explicitly being advertised as a patchset.
47+
48+
### What is missing
49+
50+
- Patch the root package / files in root directory
51+
- Allow to specify patches in the root composer.json
52+
53+
54+
55+
## Running tests
56+
57+
Just start `vendor/bin/phpunit`.
58+
If you want to see the output of commands executed during functional testing use the `--debug` switch:
59+
```
60+
vendor/bin/phpunit --debug
61+
```
62+
63+
It's nice to also add the `--testdox` switch then.
64+

composer.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "creativestyle/composer-plugin-patchset",
3+
"description": "Composer plugin that automatically applies patches from a patchset file",
4+
"type": "composer-plugin",
5+
"license": "OSL-3.0",
6+
"authors": [
7+
{
8+
"name": "Filip Sobalski",
9+
"email": "[email protected]"
10+
}
11+
],
12+
"require": {
13+
"ext-json": "*",
14+
"php": ">=5.6.0",
15+
"composer-plugin-api": "^1.1"
16+
},
17+
"require-dev": {
18+
"composer/composer": "~1.0",
19+
"composer/satis": "~1.0",
20+
"phpunit/phpunit": "^4.8.35 || ^5.7"
21+
},
22+
"autoload": {
23+
"psr-4": {"Creativestyle\\Composer\\Patchset\\": "src"}
24+
},
25+
"autoload-dev": {
26+
"psr-4": {"Creativestyle\\Composer\\Patchset\\Tests\\": "tests"}
27+
},
28+
"extra": {
29+
"class": "Creativestyle\\Composer\\Patchset\\Plugin"
30+
}
31+
}

phpunit.xml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/5.7/phpunit.xsd"
5+
bootstrap="./vendor/autoload.php"
6+
backupGlobals="true"
7+
cacheTokens="false"
8+
colors="true"
9+
>
10+
<filter>
11+
<whitelist
12+
processUncoveredFilesFromWhitelist="true">
13+
<directory suffix=".php">./src</directory>
14+
</whitelist>
15+
</filter>
16+
<testsuites>
17+
<testsuite name="Unit">
18+
<directory>./tests/Unit</directory>
19+
</testsuite>
20+
<testsuite name="Functional">
21+
<directory>./tests/Functional</directory>
22+
</testsuite>
23+
</testsuites>
24+
</phpunit>

src/IOLogger.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace Creativestyle\Composer\Patchset;
4+
5+
use Composer\IO\IOInterface;
6+
use Psr\Log\AbstractLogger;
7+
use Psr\Log\LogLevel;
8+
9+
class IOLogger extends AbstractLogger
10+
{
11+
const VERBOSITY_LEVEL_MAP = [
12+
LogLevel::DEBUG => IOInterface::DEBUG,
13+
LogLevel::INFO => IOInterface::NORMAL,
14+
LogLevel::NOTICE => IOInterface::QUIET,
15+
LogLevel::WARNING => IOInterface::QUIET,
16+
LogLevel::ERROR => IOInterface::QUIET,
17+
LogLevel::CRITICAL => IOInterface::QUIET,
18+
LogLevel::ALERT => IOInterface::QUIET,
19+
LogLevel::EMERGENCY => IOInterface::QUIET
20+
];
21+
22+
const ERROR_LEVELS = [
23+
LogLevel::ERROR,
24+
LogLevel::CRITICAL,
25+
LogLevel::ALERT,
26+
LogLevel::EMERGENCY,
27+
];
28+
29+
/**
30+
* @var IOInterface
31+
*/
32+
private $io;
33+
34+
/**
35+
* @param IOInterface $io
36+
*/
37+
public function __construct(IOInterface $io)
38+
{
39+
$this->io = $io;
40+
}
41+
42+
/**
43+
* {@inheritdoc}
44+
*/
45+
public function log($level, $message, array $context = array())
46+
{
47+
$verbosity = self::VERBOSITY_LEVEL_MAP[$level];
48+
49+
if (in_array($level, self::ERROR_LEVELS)) {
50+
$this->io->writeError($message, true, $verbosity);
51+
} else {
52+
$this->io->write($message, true, $verbosity);
53+
}
54+
}
55+
}

src/OperationResolver.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace Creativestyle\Composer\Patchset;
4+
5+
use Composer\DependencyResolver\Operation\InstallOperation;
6+
use Composer\DependencyResolver\Operation\UninstallOperation;
7+
use Composer\DependencyResolver\Operation\UpdateOperation;
8+
9+
use Composer\Installer\NoopInstaller;
10+
use Composer\Repository\InstalledArrayRepository;
11+
use Composer\Repository\RepositoryInterface;
12+
13+
class OperationResolver
14+
{
15+
/**
16+
* Returns a repository that reflects the state after operations have been executed on the current one.
17+
*
18+
* @param RepositoryInterface $repository
19+
* @param array $operations
20+
* @return RepositoryInterface
21+
*/
22+
public function resolveState(RepositoryInterface $repository, array $operations)
23+
{
24+
$packages = array_map(function($p) { return clone $p; }, $repository->getPackages());
25+
$installed = new InstalledArrayRepository($packages);
26+
$installer = new NoopInstaller();
27+
28+
foreach ($operations as $operation) {
29+
if ($operation instanceof InstallOperation) {
30+
$installer->install($installed, $operation->getPackage());
31+
} elseif ($operation instanceof UpdateOperation) {
32+
$installer->update($installed, $operation->getInitialPackage(), $operation->getTargetPackage());
33+
} elseif ($operation instanceof UninstallOperation) {
34+
$installer->uninstall($installed, $operation->getPackage());
35+
}
36+
}
37+
38+
return $installed;
39+
}
40+
}

0 commit comments

Comments
 (0)