.editorconfig 0000644 00000000360 13714573375 0007237 0 ustar 00 # This is the top-most .editorconfig file; do not search in parent directories.
root = true
# All files.
[*]
end_of_line = LF
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
.gitignore 0000644 00000000010 13714573375 0006542 0 ustar 00 vendor/
LICENSE.md 0000644 00000002661 13714573375 0006174 0 ustar 00 Copyright 2013 Cameron Eagans
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
README.md 0000644 00000013060 13714573375 0006042 0 ustar 00 # composer-patches
Simple patches plugin for Composer. Applies a patch from a local or remote file to any package required with composer.
Note that the 1.x versions of Composer Patches are supported on a best-effort
basis due to the imminent release of 2.0.0. You may still be interested in
using 1.x if you need Composer to cooperate with earlier PHP versions. No new
features will be added to 1.x releases, but any security or bug fixes will
still be accepted.
## Usage
Example composer.json:
```json
{
"require": {
"cweagans/composer-patches": "~1.0",
"drupal/drupal": "~8.2"
},
"config": {
"preferred-install": "source"
},
"extra": {
"patches": {
"drupal/drupal": {
"Add startup configuration for PHP server": "https://www.drupal.org/files/issues/add_a_startup-1543858-30.patch"
}
}
}
}
```
## Using an external patch file
Instead of a patches key in your root composer.json, use a patches-file key.
```json
{
"require": {
"cweagans/composer-patches": "~1.0",
"drupal/drupal": "~8.2"
},
"config": {
"preferred-install": "source"
},
"extra": {
"patches-file": "local/path/to/your/composer.patches.json"
}
}
```
Then your `composer.patches.json` should look like this:
```
{
"patches": {
"vendor/project": {
"Patch title": "http://example.com/url/to/patch.patch"
}
}
}
```
## Allowing patches to be applied from dependencies
If your project doesn't supply any patches of its own, but you still want to accept patches from dependencies, you must have the following in your composer file:
```json
{
"require": {
"cweagans/composer-patches": "^1.5.0"
},
"extra": {
"enable-patching": true
}
}
```
If you do have a `patches` section in your composer file that defines your own set of patches then the `enable-patching` setting will be ignored and patches from dependencies will always be applied.
## Ignoring patches
There may be situations in which you want to ignore a patch supplied by a dependency. For example:
- You use a different more recent version of a dependency, and now a patch isn't applying.
- You have a more up to date patch than the dependency, and want to use yours instead of theirs.
- A dependency's patch adds a feature to a project that you don't need.
- Your patches conflict with a dependency's patches.
```json
{
"require": {
"cweagans/composer-patches": "~1.0",
"drupal/drupal": "~8.2",
"drupal/lightning": "~8.1"
},
"config": {
"preferred-install": "source"
},
"extra": {
"patches": {
"drupal/drupal": {
"Add startup configuration for PHP server": "https://www.drupal.org/files/issues/add_a_startup-1543858-30.patch"
}
},
"patches-ignore": {
"drupal/lightning": {
"drupal/panelizer": {
"This patch has known conflicts with our Quick Edit integration": "https://www.drupal.org/files/issues/2664682-49.patch"
}
}
}
}
}
```
## Allowing to force the patch level (-pX)
Some situations require to force the patchLevel used to apply patches on a particular package.
Its useful for packages like drupal/core which packages only a subdir of the original upstream project on which patches are based.
```json
{
"extra": {
"patchLevel": {
"drupal/core": "-p2"
}
}
}
```
## Using patches from HTTP URLs
Composer [blocks](https://getcomposer.org/doc/06-config.md#secure-http) you from downloading anything from HTTP URLs, you can disable this for your project by adding a `secure-http` setting in the config section of your `composer.json`. Note that the `config` section should be under the root of your `composer.json`.
```json
{
"config": {
"secure-http": false
}
}
```
However, it's always advised to setup HTTPS to prevent MITM code injection.
## Patches containing modifications to composer.json files
Because patching occurs _after_ Composer calculates dependencies and installs packages, changes to an underlying dependency's `composer.json` file introduced in a patch will have _no effect_ on installed packages.
If you need to modify a dependency's `composer.json` or its underlying dependencies, you cannot use this plugin. Instead, you must do one of the following:
- Work to get the underlying issue resolved in the upstream package.
- Fork the package and [specify your fork as the package repository](https://getcomposer.org/doc/05-repositories.md#vcs) in your root `composer.json`
- Specify compatible package version requirements in your root `composer.json`
## Error handling
If a patch cannot be applied (hunk failed, different line endings, etc.) a message will be shown and the patch will be skipped.
To enforce throwing an error and stopping package installation/update immediately, you have two available options:
1. Add `"composer-exit-on-patch-failure": true` option to the `extra` section of your composer.json file.
1. Export `COMPOSER_EXIT_ON_PATCH_FAILURE=1`
By default, failed patches are skipped.
## Difference between this and netresearch/composer-patches-plugin
- This plugin is much more simple to use and maintain
- This plugin doesn't require you to specify which package version you're patching
- This plugin is easy to use with Drupal modules (which don't use semantic versioning).
- This plugin will gather patches from all dependencies and apply them as if they were in the root composer.json
## Credits
A ton of this code is adapted or taken straight from https://github.com/jpstacey/composer-patcher, which is abandoned in favor of https://github.com/netresearch/composer-patches-plugin, which is (IMHO) overly complex and difficult to use.
composer.json 0000644 00000001223 13714573375 0007303 0 ustar 00 {
"name": "cweagans/composer-patches",
"description": "Provides a way to patch Composer packages.",
"minimum-stability": "dev",
"license": "BSD-3-Clause",
"type": "composer-plugin",
"extra": {
"class": "cweagans\\Composer\\Patches"
},
"authors": [
{
"name": "Cameron Eagans",
"email": "me@cweagans.net"
}
],
"require": {
"php": ">=5.3.0",
"composer-plugin-api": "^1.0"
},
"require-dev": {
"composer/composer": "~1.0",
"phpunit/phpunit": "~4.6"
},
"autoload": {
"psr-4": {"cweagans\\Composer\\": "src"}
},
"autoload-dev": {
"psr-4": {"cweagans\\Composer\\Tests\\": "tests"}
}
}
composer.lock 0000644 00000152037 13714573375 0007274 0 ustar 00 {
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "a2cd6826c202b7ebefe3050efc2a7b7f",
"content-hash": "0ed9361502c0f5f22a5b440c16640193",
"packages": [],
"packages-dev": [
{
"name": "composer/composer",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/composer/composer.git",
"reference": "a54f84f05f915c6d42bed94de0cdcb4406a4707b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/composer/zipball/f2d606ae0c705907d8bfa1c6f884bced1255b827",
"reference": "a54f84f05f915c6d42bed94de0cdcb4406a4707b",
"shasum": ""
},
"require": {
"composer/semver": "^1.0",
"composer/spdx-licenses": "^1.0",
"justinrainbow/json-schema": "^1.4.4",
"php": ">=5.3.2",
"seld/cli-prompt": "~1.0",
"seld/jsonlint": "~1.0",
"seld/phar-utils": "~1.0",
"symfony/console": "~2.5",
"symfony/filesystem": "~2.5",
"symfony/finder": "~2.2",
"symfony/process": "~2.1"
},
"require-dev": {
"phpunit/phpunit": "~4.5|^5.0.5",
"phpunit/phpunit-mock-objects": "2.3.0|~3.0"
},
"suggest": {
"ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages",
"ext-zip": "Enabling the zip extension allows you to unzip archives, and allows gzip compression of all internet traffic"
},
"bin": [
"bin/composer"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-0": {
"Composer": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nils Adermann",
"email": "naderman@naderman.de",
"homepage": "http://www.naderman.de"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "Composer helps you declare, manage and install dependencies of PHP projects, ensuring you have the right stack everywhere.",
"homepage": "https://getcomposer.org/",
"keywords": [
"autoload",
"dependency",
"package"
],
"time": "2015-10-13 13:09:04"
},
{
"name": "composer/semver",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "d0e1ccc6d44ab318b758d709e19176037da6b1ba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/d0e1ccc6d44ab318b758d709e19176037da6b1ba",
"reference": "d0e1ccc6d44ab318b758d709e19176037da6b1ba",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "~4.5",
"phpunit/phpunit-mock-objects": "~2.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.1-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Semver\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rob Bast",
"email": "rob.bast@gmail.com"
},
{
"name": "Nils Adermann",
"email": "naderman@naderman.de",
"homepage": "http://www.naderman.de"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "Semver library that offers utilities, version constraint parsing and validation.",
"keywords": [
"semantic",
"semver",
"validation",
"versioning"
],
"time": "2015-09-21 09:42:36"
},
{
"name": "composer/spdx-licenses",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/composer/spdx-licenses.git",
"reference": "b2dbc76d1c3f81f33857cdd49c0be6ce7b87897d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/spdx-licenses/zipball/022fc25ca664f612b1e7007e0d87642ef489f000",
"reference": "b2dbc76d1c3f81f33857cdd49c0be6ce7b87897d",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "~4.5",
"phpunit/phpunit-mock-objects": "~2.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Spdx\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nils Adermann",
"email": "naderman@naderman.de",
"homepage": "http://www.naderman.de"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
},
{
"name": "Rob Bast",
"email": "rob.bast@gmail.com",
"homepage": "http://robbast.nl"
}
],
"description": "SPDX licenses list and validation library.",
"keywords": [
"license",
"spdx",
"validator"
],
"time": "2015-10-05 11:33:06"
},
{
"name": "doctrine/instantiator",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
"shasum": ""
},
"require": {
"php": ">=5.3,<8.0-DEV"
},
"require-dev": {
"athletic/athletic": "~0.1.8",
"ext-pdo": "*",
"ext-phar": "*",
"phpunit/phpunit": "~4.0",
"squizlabs/php_codesniffer": "~2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com",
"homepage": "http://ocramius.github.com/"
}
],
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
"homepage": "https://github.com/doctrine/instantiator",
"keywords": [
"constructor",
"instantiate"
],
"time": "2015-06-14 21:17:01"
},
{
"name": "justinrainbow/json-schema",
"version": "1.5.0",
"source": {
"type": "git",
"url": "https://github.com/justinrainbow/json-schema.git",
"reference": "a4bee9f4b344b66e0a0d96c7afae1e92edf385fe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/a4bee9f4b344b66e0a0d96c7afae1e92edf385fe",
"reference": "a4bee9f4b344b66e0a0d96c7afae1e92edf385fe",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"json-schema/json-schema-test-suite": "1.1.0",
"phpdocumentor/phpdocumentor": "~2",
"phpunit/phpunit": "~3.7"
},
"bin": [
"bin/validate-json"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4.x-dev"
}
},
"autoload": {
"psr-4": {
"JsonSchema\\": "src/JsonSchema/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Bruno Prieto Reis",
"email": "bruno.p.reis@gmail.com"
},
{
"name": "Justin Rainbow",
"email": "justin.rainbow@gmail.com"
},
{
"name": "Igor Wiedler",
"email": "igor@wiedler.ch"
},
{
"name": "Robert Schönthal",
"email": "seroscho@googlemail.com"
}
],
"description": "A library to validate a json schema.",
"homepage": "https://github.com/justinrainbow/json-schema",
"keywords": [
"json",
"schema"
],
"time": "2015-09-08 22:28:04"
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "2.0.4",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8",
"reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"suggest": {
"dflydev/markdown": "~1.0",
"erusev/parsedown": "~1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-0": {
"phpDocumentor": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike van Riel",
"email": "mike.vanriel@naenius.com"
}
],
"time": "2015-02-03 12:10:50"
},
{
"name": "phpspec/prophecy",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "4f9b1eaf0a7da77c362f8d91cbc68ab1f4718d62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/b02221e42163be673f9b44a0bc92a8b4907a7c6d",
"reference": "4f9b1eaf0a7da77c362f8d91cbc68ab1f4718d62",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"phpdocumentor/reflection-docblock": "~2.0",
"sebastian/comparator": "~1.1"
},
"require-dev": {
"phpspec/phpspec": "~2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.5.x-dev"
}
},
"autoload": {
"psr-0": {
"Prophecy\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Konstantin Kudryashov",
"email": "ever.zet@gmail.com",
"homepage": "http://everzet.com"
},
{
"name": "Marcello Duarte",
"email": "marcello.duarte@gmail.com"
}
],
"description": "Highly opinionated mocking framework for PHP 5.3+",
"homepage": "https://github.com/phpspec/prophecy",
"keywords": [
"Double",
"Dummy",
"fake",
"mock",
"spy",
"stub"
],
"time": "2015-09-22 14:49:23"
},
{
"name": "phpunit/php-code-coverage",
"version": "2.2.x-dev",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
"reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"phpunit/php-file-iterator": "~1.3",
"phpunit/php-text-template": "~1.2",
"phpunit/php-token-stream": "~1.3",
"sebastian/environment": "^1.3.2",
"sebastian/version": "~1.0"
},
"require-dev": {
"ext-xdebug": ">=2.1.4",
"phpunit/phpunit": "~4"
},
"suggest": {
"ext-dom": "*",
"ext-xdebug": ">=2.2.1",
"ext-xmlwriter": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
"homepage": "https://github.com/sebastianbergmann/php-code-coverage",
"keywords": [
"coverage",
"testing",
"xunit"
],
"time": "2015-10-06 15:47:00"
},
{
"name": "phpunit/php-file-iterator",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
"reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "FilterIterator implementation that filters files based on a list of suffixes.",
"homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
"keywords": [
"filesystem",
"iterator"
],
"time": "2015-06-21 13:08:43"
},
{
"name": "phpunit/php-text-template",
"version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-text-template.git",
"reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
"reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Simple template engine.",
"homepage": "https://github.com/sebastianbergmann/php-text-template/",
"keywords": [
"template"
],
"time": "2015-06-21 13:50:34"
},
{
"name": "phpunit/php-timer",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
"reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
"reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Utility class for timing",
"homepage": "https://github.com/sebastianbergmann/php-timer/",
"keywords": [
"timer"
],
"time": "2015-06-21 08:01:12"
},
{
"name": "phpunit/php-token-stream",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "cab6c6fefee93d7b7c3a01292a0fe0884ea66644"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/cab6c6fefee93d7b7c3a01292a0fe0884ea66644",
"reference": "cab6c6fefee93d7b7c3a01292a0fe0884ea66644",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Wrapper around PHP's tokenizer extension.",
"homepage": "https://github.com/sebastianbergmann/php-token-stream/",
"keywords": [
"tokenizer"
],
"time": "2015-09-23 14:46:55"
},
{
"name": "phpunit/phpunit",
"version": "4.8.x-dev",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "be067d6105286b74272facefc2697038f8807b77"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/264188ddf4d3586c80ea615f8ec8eaea34e652a1",
"reference": "be067d6105286b74272facefc2697038f8807b77",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-json": "*",
"ext-pcre": "*",
"ext-reflection": "*",
"ext-spl": "*",
"php": ">=5.3.3",
"phpspec/prophecy": "^1.3.1",
"phpunit/php-code-coverage": "~2.1",
"phpunit/php-file-iterator": "~1.4",
"phpunit/php-text-template": "~1.2",
"phpunit/php-timer": ">=1.0.6",
"phpunit/phpunit-mock-objects": "~2.3",
"sebastian/comparator": "~1.1",
"sebastian/diff": "~1.2",
"sebastian/environment": "~1.3",
"sebastian/exporter": "~1.2",
"sebastian/global-state": "~1.0",
"sebastian/version": "~1.0",
"symfony/yaml": "~2.1|~3.0"
},
"suggest": {
"phpunit/php-invoker": "~1.1"
},
"bin": [
"phpunit"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.8.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "The PHP Unit Testing framework.",
"homepage": "https://phpunit.de/",
"keywords": [
"phpunit",
"testing",
"xunit"
],
"time": "2015-10-14 13:49:40"
},
{
"name": "phpunit/phpunit-mock-objects",
"version": "2.3.x-dev",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
"reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
"reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": ">=5.3.3",
"phpunit/php-text-template": "~1.2",
"sebastian/exporter": "~1.2"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
},
"suggest": {
"ext-soap": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Mock Object library for PHPUnit",
"homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
"keywords": [
"mock",
"xunit"
],
"time": "2015-10-02 06:51:40"
},
{
"name": "sebastian/comparator",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "937efb279bd37a375bcadf584dec0726f84dbf22"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22",
"reference": "937efb279bd37a375bcadf584dec0726f84dbf22",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"sebastian/diff": "~1.2",
"sebastian/exporter": "~1.2"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
"name": "Volker Dusch",
"email": "github@wallbash.com"
},
{
"name": "Bernhard Schussek",
"email": "bschussek@2bepublished.at"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Provides the functionality to compare PHP values for equality",
"homepage": "http://www.github.com/sebastianbergmann/comparator",
"keywords": [
"comparator",
"compare",
"equality"
],
"time": "2015-07-26 15:48:44"
},
{
"name": "sebastian/diff",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
"reference": "6899b3e33bfbd386d88b5eea5f65f563e8793051"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e",
"reference": "6899b3e33bfbd386d88b5eea5f65f563e8793051",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Kore Nordmann",
"email": "mail@kore-nordmann.de"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Diff implementation",
"homepage": "http://www.github.com/sebastianbergmann/diff",
"keywords": [
"diff"
],
"time": "2015-06-22 14:15:55"
},
{
"name": "sebastian/environment",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "6324c907ce7a52478eeeaede764f48733ef5ae44"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
"reference": "6324c907ce7a52478eeeaede764f48733ef5ae44",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Provides functionality to handle HHVM/PHP environments",
"homepage": "http://www.github.com/sebastianbergmann/environment",
"keywords": [
"Xdebug",
"environment",
"hhvm"
],
"time": "2015-08-03 06:14:51"
},
{
"name": "sebastian/exporter",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "f88f8936517d54ae6d589166810877fb2015d0a2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/f88f8936517d54ae6d589166810877fb2015d0a2",
"reference": "f88f8936517d54ae6d589166810877fb2015d0a2",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"sebastian/recursion-context": "~1.0"
},
"require-dev": {
"ext-mbstring": "*",
"phpunit/phpunit": "~4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
"name": "Volker Dusch",
"email": "github@wallbash.com"
},
{
"name": "Bernhard Schussek",
"email": "bschussek@2bepublished.at"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
},
{
"name": "Adam Harvey",
"email": "aharvey@php.net"
}
],
"description": "Provides the functionality to export PHP variables for visualization",
"homepage": "http://www.github.com/sebastianbergmann/exporter",
"keywords": [
"export",
"exporter"
],
"time": "2015-08-09 04:23:41"
},
{
"name": "sebastian/global-state",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
"reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.2"
},
"suggest": {
"ext-uopz": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Snapshotting of global state",
"homepage": "http://www.github.com/sebastianbergmann/global-state",
"keywords": [
"global state"
],
"time": "2015-10-12 03:26:01"
},
{
"name": "sebastian/recursion-context",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
"reference": "994d4a811bafe801fb06dccbee797863ba2792ba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/7ff5b1b3dcc55b8ab8ae61ef99d4730940856ee7",
"reference": "994d4a811bafe801fb06dccbee797863ba2792ba",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
},
{
"name": "Adam Harvey",
"email": "aharvey@php.net"
}
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
"time": "2015-06-21 08:04:50"
},
{
"name": "sebastian/version",
"version": "1.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/version.git",
"reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
"reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
"shasum": ""
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
"time": "2015-06-21 13:59:46"
},
{
"name": "seld/cli-prompt",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/cli-prompt.git",
"reference": "fe114c7a6ac5cb0ce76932ae4017024d9842a49c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/b27db1514f7d7bb7a366ad95d4eb2b17140a0691",
"reference": "fe114c7a6ac5cb0ce76932ae4017024d9842a49c",
"shasum": ""
},
"require": {
"php": ">=5.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Seld\\CliPrompt\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be"
}
],
"description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type",
"keywords": [
"cli",
"console",
"hidden",
"input",
"prompt"
],
"time": "2015-04-30 20:24:49"
},
{
"name": "seld/jsonlint",
"version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/jsonlint.git",
"reference": "863ae85c6d3ef60ca49cb12bd051c4a0648c40c4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/863ae85c6d3ef60ca49cb12bd051c4a0648c40c4",
"reference": "863ae85c6d3ef60ca49cb12bd051c4a0648c40c4",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"bin": [
"bin/jsonlint"
],
"type": "library",
"autoload": {
"psr-4": {
"Seld\\JsonLint\\": "src/Seld/JsonLint/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "JSON Linter",
"keywords": [
"json",
"linter",
"parser",
"validator"
],
"time": "2015-01-04 21:18:15"
},
{
"name": "seld/phar-utils",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/phar-utils.git",
"reference": "7009b5139491975ef6486545a39f3e6dad5ac30a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/7009b5139491975ef6486545a39f3e6dad5ac30a",
"reference": "7009b5139491975ef6486545a39f3e6dad5ac30a",
"shasum": ""
},
"require": {
"php": ">=5.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Seld\\PharUtils\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be"
}
],
"description": "PHAR file format utilities, for when PHP phars you up",
"keywords": [
"phra"
],
"time": "2015-10-13 18:44:15"
},
{
"name": "symfony/console",
"version": "2.8.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "89a795226477f66745e8ea10415e769304114920"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/56cc5caf051189720b8de974e4746090aaa10d44",
"reference": "89a795226477f66745e8ea10415e769304114920",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/event-dispatcher": "~2.1|~3.0.0",
"symfony/process": "~2.1|~3.0.0"
},
"suggest": {
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/process": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2015-10-12 10:31:17"
},
{
"name": "symfony/filesystem",
"version": "2.8.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "fc3fe52fef85e1f3e7775ffad92539e16c20e0af"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/65cb36b6539b1d446527d60457248f30d045464d",
"reference": "fc3fe52fef85e1f3e7775ffad92539e16c20e0af",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Filesystem\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
"time": "2015-10-11 08:29:26"
},
{
"name": "symfony/finder",
"version": "2.8.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "dcd5aaba34ca332abb7f33ec554ebd4d829cb202"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/877bb4b16ea573cc8c024e9590888fcf7eb7e0f7",
"reference": "dcd5aaba34ca332abb7f33ec554ebd4d829cb202",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Finder\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
"time": "2015-10-11 08:29:26"
},
{
"name": "symfony/process",
"version": "2.8.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "4e1daf58b375ea7c506d525dc7801df1c9a6ebbd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/7dedd5b60550f33dca16dd7e94ef8aca8b67bbfe",
"reference": "4e1daf58b375ea7c506d525dc7801df1c9a6ebbd",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Process\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"time": "2015-10-11 08:29:26"
},
{
"name": "symfony/yaml",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "8d32eb597b531eb915b4fee3dc582ade5ae1fe6a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/ab0314f7544d600ea7917f02cdad774358b81113",
"reference": "8d32eb597b531eb915b4fee3dc582ade5ae1fe6a",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2015-10-13 16:01:35"
}
],
"aliases": [],
"minimum-stability": "dev",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=5.3.0"
},
"platform-dev": []
}
phpunit.xml.dist 0000644 00000000670 13714573375 0007741 0 ustar 00
./tests/
src/
vendor/
src/PatchEvent.php 0000644 00000002317 13714573375 0010127 0 ustar 00 package = $package;
$this->url = $url;
$this->description = $description;
}
/**
* Returns the package that is patched.
*
* @return PackageInterface
*/
public function getPackage() {
return $this->package;
}
/**
* Returns the url of the patch.
*
* @return string
*/
public function getUrl() {
return $this->url;
}
/**
* Returns the description of the patch.
*
* @return string
*/
public function getDescription() {
return $this->description;
}
}
src/PatchEvents.php 0000644 00000001113 13714573375 0010303 0 ustar 00 composer = $composer;
$this->io = $io;
$this->eventDispatcher = $composer->getEventDispatcher();
$this->executor = new ProcessExecutor($this->io);
$this->patches = array();
$this->installedPatches = array();
}
/**
* Returns an array of event names this subscriber wants to listen to.
*/
public static function getSubscribedEvents() {
return array(
ScriptEvents::PRE_INSTALL_CMD => array('checkPatches'),
ScriptEvents::PRE_UPDATE_CMD => array('checkPatches'),
PackageEvents::PRE_PACKAGE_INSTALL => array('gatherPatches'),
PackageEvents::PRE_PACKAGE_UPDATE => array('gatherPatches'),
// The following is a higher weight for compatibility with
// https://github.com/AydinHassan/magento-core-composer-installer and more generally for compatibility with
// every Composer plugin which deploys downloaded packages to other locations.
// In such cases you want that those plugins deploy patched files so they have to run after
// the "composer-patches" plugin.
// @see: https://github.com/cweagans/composer-patches/pull/153
PackageEvents::POST_PACKAGE_INSTALL => array('postInstall', 10),
PackageEvents::POST_PACKAGE_UPDATE => array('postInstall', 10),
);
}
/**
* Before running composer install,
* @param Event $event
*/
public function checkPatches(Event $event) {
if (!$this->isPatchingEnabled()) {
return;
}
try {
$repositoryManager = $this->composer->getRepositoryManager();
$localRepository = $repositoryManager->getLocalRepository();
$installationManager = $this->composer->getInstallationManager();
$packages = $localRepository->getPackages();
$extra = $this->composer->getPackage()->getExtra();
$patches_ignore = isset($extra['patches-ignore']) ? $extra['patches-ignore'] : array();
$tmp_patches = $this->grabPatches();
foreach ($packages as $package) {
$extra = $package->getExtra();
if (isset($extra['patches'])) {
if (isset($patches_ignore[$package->getName()])) {
foreach ($patches_ignore[$package->getName()] as $package_name => $patches) {
if (isset($extra['patches'][$package_name])) {
$extra['patches'][$package_name] = array_diff($extra['patches'][$package_name], $patches);
}
}
}
$this->installedPatches[$package->getName()] = $extra['patches'];
}
$patches = isset($extra['patches']) ? $extra['patches'] : array();
$tmp_patches = $this->arrayMergeRecursiveDistinct($tmp_patches, $patches);
}
if ($tmp_patches == FALSE) {
$this->io->write('No patches supplied.');
return;
}
// Remove packages for which the patch set has changed.
foreach ($packages as $package) {
if (!($package instanceof AliasPackage)) {
$package_name = $package->getName();
$extra = $package->getExtra();
$has_patches = isset($tmp_patches[$package_name]);
$has_applied_patches = isset($extra['patches_applied']) && count($extra['patches_applied']) > 0;
if (($has_patches && !$has_applied_patches)
|| (!$has_patches && $has_applied_patches)
|| ($has_patches && $has_applied_patches && $tmp_patches[$package_name] !== $extra['patches_applied'])) {
$uninstallOperation = new UninstallOperation($package, 'Removing package so it can be re-installed and re-patched.');
$this->io->write('Removing package ' . $package_name . ' so that it can be re-installed and re-patched.');
$installationManager->uninstall($localRepository, $uninstallOperation);
}
}
}
}
// If the Locker isn't available, then we don't need to do this.
// It's the first time packages have been installed.
catch (\LogicException $e) {
return;
}
}
/**
* Gather patches from dependencies and store them for later use.
*
* @param PackageEvent $event
*/
public function gatherPatches(PackageEvent $event) {
// If we've already done this, then don't do it again.
if (isset($this->patches['_patchesGathered'])) {
$this->io->write('Patches already gathered. Skipping', TRUE, IOInterface::VERBOSE);
return;
}
// If patching has been disabled, bail out here.
elseif (!$this->isPatchingEnabled()) {
$this->io->write('Patching is disabled. Skipping.', TRUE, IOInterface::VERBOSE);
return;
}
$this->patches = $this->grabPatches();
if (empty($this->patches)) {
$this->io->write('No patches supplied.');
}
$extra = $this->composer->getPackage()->getExtra();
$patches_ignore = isset($extra['patches-ignore']) ? $extra['patches-ignore'] : array();
// Now add all the patches from dependencies that will be installed.
$operations = $event->getOperations();
$this->io->write('Gathering patches for dependencies. This might take a minute.');
foreach ($operations as $operation) {
if ($operation->getJobType() == 'install' || $operation->getJobType() == 'update') {
$package = $this->getPackageFromOperation($operation);
$extra = $package->getExtra();
if (isset($extra['patches'])) {
if (isset($patches_ignore[$package->getName()])) {
foreach ($patches_ignore[$package->getName()] as $package_name => $patches) {
if (isset($extra['patches'][$package_name])) {
$extra['patches'][$package_name] = array_diff($extra['patches'][$package_name], $patches);
}
}
}
$this->patches = $this->arrayMergeRecursiveDistinct($this->patches, $extra['patches']);
}
// Unset installed patches for this package
if(isset($this->installedPatches[$package->getName()])) {
unset($this->installedPatches[$package->getName()]);
}
}
}
// Merge installed patches from dependencies that did not receive an update.
foreach ($this->installedPatches as $patches) {
$this->patches = $this->arrayMergeRecursiveDistinct($this->patches, $patches);
}
// If we're in verbose mode, list the projects we're going to patch.
if ($this->io->isVerbose()) {
foreach ($this->patches as $package => $patches) {
$number = count($patches);
$this->io->write('Found ' . $number . ' patches for ' . $package . '.');
}
}
// Make sure we don't gather patches again. Extra keys in $this->patches
// won't hurt anything, so we'll just stash it there.
$this->patches['_patchesGathered'] = TRUE;
}
/**
* Get the patches from root composer or external file
* @return Patches
* @throws \Exception
*/
public function grabPatches() {
// First, try to get the patches from the root composer.json.
$extra = $this->composer->getPackage()->getExtra();
if (isset($extra['patches'])) {
$this->io->write('Gathering patches for root package.');
$patches = $extra['patches'];
return $patches;
}
// If it's not specified there, look for a patches-file definition.
elseif (isset($extra['patches-file'])) {
$this->io->write('Gathering patches from patch file.');
$patches = file_get_contents($extra['patches-file']);
$patches = json_decode($patches, TRUE);
$error = json_last_error();
if ($error != 0) {
switch ($error) {
case JSON_ERROR_DEPTH:
$msg = ' - Maximum stack depth exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
$msg = ' - Underflow or the modes mismatch';
break;
case JSON_ERROR_CTRL_CHAR:
$msg = ' - Unexpected control character found';
break;
case JSON_ERROR_SYNTAX:
$msg = ' - Syntax error, malformed JSON';
break;
case JSON_ERROR_UTF8:
$msg = ' - Malformed UTF-8 characters, possibly incorrectly encoded';
break;
default:
$msg = ' - Unknown error';
break;
}
throw new \Exception('There was an error in the supplied patches file:' . $msg);
}
if (isset($patches['patches'])) {
$patches = $patches['patches'];
return $patches;
}
elseif(!$patches) {
throw new \Exception('There was an error in the supplied patch file');
}
}
else {
return array();
}
}
/**
* @param PackageEvent $event
* @throws \Exception
*/
public function postInstall(PackageEvent $event) {
// Check if we should exit in failure.
$extra = $this->composer->getPackage()->getExtra();
$exitOnFailure = getenv('COMPOSER_EXIT_ON_PATCH_FAILURE') || !empty($extra['composer-exit-on-patch-failure']);
// Get the package object for the current operation.
$operation = $event->getOperation();
/** @var PackageInterface $package */
$package = $this->getPackageFromOperation($operation);
$package_name = $package->getName();
if (!isset($this->patches[$package_name])) {
if ($this->io->isVerbose()) {
$this->io->write('No patches found for ' . $package_name . '.');
}
return;
}
$this->io->write(' - Applying patches for ' . $package_name . '');
// Get the install path from the package object.
$manager = $event->getComposer()->getInstallationManager();
$install_path = $manager->getInstaller($package->getType())->getInstallPath($package);
// Set up a downloader.
$downloader = new RemoteFilesystem($this->io, $this->composer->getConfig());
// Track applied patches in the package info in installed.json
$localRepository = $this->composer->getRepositoryManager()->getLocalRepository();
$localPackage = $localRepository->findPackage($package_name, $package->getVersion());
$extra = $localPackage->getExtra();
$extra['patches_applied'] = array();
foreach ($this->patches[$package_name] as $description => $url) {
$this->io->write(' ' . $url . ' (' . $description. ')');
try {
$this->eventDispatcher->dispatch(NULL, new PatchEvent(PatchEvents::PRE_PATCH_APPLY, $package, $url, $description));
$this->getAndApplyPatch($downloader, $install_path, $url, $package);
$this->eventDispatcher->dispatch(NULL, new PatchEvent(PatchEvents::POST_PATCH_APPLY, $package, $url, $description));
$extra['patches_applied'][$description] = $url;
}
catch (\Exception $e) {
$this->io->write(' Could not apply patch! Skipping. The error was: ' . $e->getMessage() . '');
if ($exitOnFailure) {
throw new \Exception("Cannot apply patch $description ($url)!");
}
}
}
$localPackage->setExtra($extra);
$this->io->write('');
$this->writePatchReport($this->patches[$package_name], $install_path);
}
/**
* Get a Package object from an OperationInterface object.
*
* @param OperationInterface $operation
* @return PackageInterface
* @throws \Exception
*/
protected function getPackageFromOperation(OperationInterface $operation) {
if ($operation instanceof InstallOperation) {
$package = $operation->getPackage();
}
elseif ($operation instanceof UpdateOperation) {
$package = $operation->getTargetPackage();
}
else {
throw new \Exception('Unknown operation: ' . get_class($operation));
}
return $package;
}
/**
* Apply a patch on code in the specified directory.
*
* @param RemoteFilesystem $downloader
* @param $install_path
* @param $patch_url
* @param PackageInterface $package
* @throws \Exception
*/
protected function getAndApplyPatch(RemoteFilesystem $downloader, $install_path, $patch_url, PackageInterface $package) {
// Local patch file.
if (file_exists($patch_url)) {
$filename = realpath($patch_url);
}
else {
// Generate random (but not cryptographically so) filename.
$filename = uniqid(sys_get_temp_dir().'/') . ".patch";
// Download file from remote filesystem to this location.
$hostname = parse_url($patch_url, PHP_URL_HOST);
try {
$downloader->copy($hostname, $patch_url, $filename, false);
} catch (\Exception $e) {
// In case of an exception, retry once as the download might
// have failed due to intermittent network issues.
$downloader->copy($hostname, $patch_url, $filename, false);
}
}
// The order here is intentional. p1 is most likely to apply with git apply.
// p0 is next likely. p2 is extremely unlikely, but for some special cases,
// it might be useful. p4 is useful for Magento 2 patches
$patch_levels = array('-p1', '-p0', '-p2', '-p4');
// Check for specified patch level for this package.
$extra = $this->composer->getPackage()->getExtra();
if (!empty($extra['patchLevel'][$package->getName()])){
$patch_levels = array($extra['patchLevel'][$package->getName()]);
}
// Attempt to apply with git apply.
$patched = $this->applyPatchWithGit($install_path, $patch_levels, $filename);
// In some rare cases, git will fail to apply a patch, fallback to using
// the 'patch' command.
if (!$patched) {
foreach ($patch_levels as $patch_level) {
// --no-backup-if-mismatch here is a hack that fixes some
// differences between how patch works on windows and unix.
if ($patched = $this->executeCommand("patch %s --no-backup-if-mismatch -d %s < %s", $patch_level, $install_path, $filename)) {
break;
}
}
}
// Clean up the temporary patch file.
if (isset($hostname)) {
unlink($filename);
}
// If the patch *still* isn't applied, then give up and throw an Exception.
// Otherwise, let the user know it worked.
if (!$patched) {
throw new \Exception("Cannot apply patch $patch_url");
}
}
/**
* Checks if the root package enables patching.
*
* @return bool
* Whether patching is enabled. Defaults to TRUE.
*/
protected function isPatchingEnabled() {
$extra = $this->composer->getPackage()->getExtra();
if (empty($extra['patches']) && empty($extra['patches-ignore']) && !isset($extra['patches-file'])) {
// The root package has no patches of its own, so only allow patching if
// it has specifically opted in.
return isset($extra['enable-patching']) ? $extra['enable-patching'] : FALSE;
}
else {
return TRUE;
}
}
/**
* Writes a patch report to the target directory.
*
* @param array $patches
* @param string $directory
*/
protected function writePatchReport($patches, $directory) {
$output = "This file was automatically generated by Composer Patches (https://github.com/cweagans/composer-patches)\n";
$output .= "Patches applied to this directory:\n\n";
foreach ($patches as $description => $url) {
$output .= $description . "\n";
$output .= 'Source: ' . $url . "\n\n\n";
}
file_put_contents($directory . "/PATCHES.txt", $output);
}
/**
* Executes a shell command with escaping.
*
* @param string $cmd
* @return bool
*/
protected function executeCommand($cmd) {
// Shell-escape all arguments except the command.
$args = func_get_args();
foreach ($args as $index => $arg) {
if ($index !== 0) {
$args[$index] = escapeshellarg($arg);
}
}
// And replace the arguments.
$command = call_user_func_array('sprintf', $args);
$output = '';
if ($this->io->isVerbose()) {
$this->io->write('' . $command . '');
$io = $this->io;
$output = function ($type, $data) use ($io) {
if ($type == Process::ERR) {
$io->write('' . $data . '');
}
else {
$io->write('' . $data . '');
}
};
}
return ($this->executor->execute($command, $output) == 0);
}
/**
* Recursively merge arrays without changing data types of values.
*
* Does not change the data types of the values in the arrays. Matching keys'
* values in the second array overwrite those in the first array, as is the
* case with array_merge.
*
* @param array $array1
* The first array.
* @param array $array2
* The second array.
* @return array
* The merged array.
*
* @see http://php.net/manual/en/function.array-merge-recursive.php#92195
*/
protected function arrayMergeRecursiveDistinct(array $array1, array $array2) {
$merged = $array1;
foreach ($array2 as $key => &$value) {
if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
$merged[$key] = $this->arrayMergeRecursiveDistinct($merged[$key], $value);
}
else {
$merged[$key] = $value;
}
}
return $merged;
}
/**
* Attempts to apply a patch with git apply.
*
* @param $install_path
* @param $patch_levels
* @param $filename
*
* @return bool
* TRUE if patch was applied, FALSE otherwise.
*/
protected function applyPatchWithGit($install_path, $patch_levels, $filename) {
// Do not use git apply unless the install path is itself a git repo
// @see https://stackoverflow.com/a/27283285
if (!is_dir($install_path . '/.git')) {
return FALSE;
}
$patched = FALSE;
foreach ($patch_levels as $patch_level) {
if ($this->io->isVerbose()) {
$comment = 'Testing ability to patch with git apply.';
$comment .= ' This command may produce errors that can be safely ignored.';
$this->io->write('' . $comment . '');
}
$checked = $this->executeCommand('git -C %s apply --check -v %s %s', $install_path, $patch_level, $filename);
$output = $this->executor->getErrorOutput();
if (substr($output, 0, 7) == 'Skipped') {
// Git will indicate success but silently skip patches in some scenarios.
//
// @see https://github.com/cweagans/composer-patches/pull/165
$checked = FALSE;
}
if ($checked) {
// Apply the first successful style.
$patched = $this->executeCommand('git -C %s apply %s %s', $install_path, $patch_level, $filename);
break;
}
}
return $patched;
}
}
tests/PatchEventTest.php 0000644 00000002175 13714573375 0011344 0 ustar 00 assertEquals($event_name, $patch_event->getName());
$this->assertEquals($package, $patch_event->getPackage());
$this->assertEquals($url, $patch_event->getUrl());
$this->assertEquals($description, $patch_event->getDescription());
}
public function patchEventDataProvider() {
$prophecy = $this->prophesize('Composer\Package\PackageInterface');
$package = $prophecy->reveal();
return array(
array(PatchEvents::PRE_PATCH_APPLY, $package, 'https://www.drupal.org', 'A test patch'),
array(PatchEvents::POST_PATCH_APPLY, $package, 'https://www.drupal.org', 'A test patch'),
);
}
}