diff --git a/composer.json b/composer.json index aa3b88b4..a26f4dba 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,8 @@ ], "require": { "php": ">=5.6.0", - "composer-plugin-api": "^1.0" + "composer-plugin-api": "^1.0", + "cweagans/composer-configurable-plugin": "^1.0" }, "require-dev": { "composer/composer": "~1.0", diff --git a/composer.lock b/composer.lock index 84db7e0c..a4433904 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,49 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "4083a703b8ed2ed7ff5cff34c8a226c6", - "packages": [], + "content-hash": "22bc9b56528428a17f52fed1908da23c", + "packages": [ + { + "name": "cweagans/composer-configurable-plugin", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/cweagans/composer-configurable-plugin.git", + "reference": "2df389bb1f13830fd95461d51f6eb52d02fc1c21" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cweagans/composer-configurable-plugin/zipball/2df389bb1f13830fd95461d51f6eb52d02fc1c21", + "reference": "2df389bb1f13830fd95461d51f6eb52d02fc1c21", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "composer/composer": "~1.0", + "phpunit/phpunit": "~5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "cweagans\\Composer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Cameron Eagans", + "email": "me@cweagans.net" + } + ], + "description": "Provides a lightweight configuration system for Composer plugins.", + "time": "2017-05-25T04:32:06+00:00" + } + ], "packages-dev": [ { "name": "behat/gherkin", diff --git a/src/Patches.php b/src/Patches.php index 975f306e..985da43d 100644 --- a/src/Patches.php +++ b/src/Patches.php @@ -28,22 +28,28 @@ class Patches implements PluginInterface, EventSubscriberInterface { + use ConfigurablePlugin; + /** * @var Composer $composer */ protected $composer; + /** * @var IOInterface $io */ protected $io; + /** * @var EventDispatcher $eventDispatcher */ protected $eventDispatcher; + /** * @var ProcessExecutor $executor */ protected $executor; + /** * @var array $patches */ @@ -63,6 +69,34 @@ public function activate(Composer $composer, IOInterface $io) $this->executor = new ProcessExecutor($this->io); $this->patches = array(); $this->installedPatches = array(); + + $this->configuration = [ + 'exit-on-patch-failure' => [ + 'type' => 'bool', + 'default' => true, + ], + 'disable-patching' => [ + 'type' => 'bool', + 'default' => false, + ], + 'disable-patching-from-dependencies' => [ + 'type' => 'bool', + 'default' => false, + ], + 'disable-patch-reports' => [ + 'type' => 'bool', + 'default' => false, + ], + 'patch-levels' => [ + 'type' => 'list', + 'default' => ['-p1', '-p0', '-p2', '-p4'] + ], + 'patches-file' => [ + 'type' => 'string', + 'default' => '', + ] + ]; + $this->configure($this->composer->getPackage()->getExtra(), 'composer-patches'); } /** @@ -172,28 +206,30 @@ public function gatherPatches(PackageEvent $event) $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 - ); + if (!$this->getConfig('disable-patching-from-dependencies')) { + $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()]); } - $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()]); } } } @@ -230,9 +266,9 @@ public function grabPatches() $patches = $extra['patches']; return $patches; } // If it's not specified there, look for a patches-file definition. - elseif (isset($extra['patches-file'])) { + elseif ($this->getConfig('patches-file') != '') { $this->io->write('Gathering patches from patch file.'); - $patches = file_get_contents($extra['patches-file']); + $patches = file_get_contents($this->getConfig('patches-file')); $patches = json_decode($patches, true); $error = json_last_error(); if ($error != 0) { @@ -275,10 +311,6 @@ public function grabPatches() */ 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 */ @@ -325,7 +357,7 @@ public function postInstall(PackageEvent $event) $e->getMessage() . '' ); - if ($exitOnFailure) { + if ($this->getConfig('exit-on-patch-failure')) { throw new \Exception("Cannot apply patch $description ($url)!"); } } @@ -384,7 +416,7 @@ protected function getAndApplyPatch(RemoteFilesystem $downloader, $install_path, // 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'); + $patch_levels = $this->getConfig('patch-levels'); foreach ($patch_levels as $patch_level) { if ($this->io->isVerbose()) { $comment = 'Testing ability to patch with git apply.'; @@ -453,15 +485,17 @@ protected function getAndApplyPatch(RemoteFilesystem $downloader, $install_path, */ protected function isPatchingEnabled() { - $extra = $this->composer->getPackage()->getExtra(); + $enabled = true; - 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; + $has_no_patches = empty($extra['patches']); + $has_no_patches_file = ($this->getConfig('patches-file') == ''); + $patching_disabled = $this->getConfig('disable-patching'); + + if ($patching_disabled || !($has_no_patches && $has_no_patches_file)) { + $enabled = false; } + + return $enabled; } /** @@ -472,6 +506,10 @@ protected function isPatchingEnabled() */ protected function writePatchReport($patches, $directory) { + if ($this->getConfig('disable-patch-reports')) { + return; + } + $output = "This file was automatically generated by Composer Patches"; $output .= " (https://github.com/cweagans/composer-patches)\n"; $output .= "Patches applied to this directory:\n\n"; diff --git a/tests/acceptance/fixtures/patches-file-patch-from-web/composer.json b/tests/acceptance/fixtures/patches-file-patch-from-web/composer.json index 7ff99527..a28dd92c 100644 --- a/tests/acceptance/fixtures/patches-file-patch-from-web/composer.json +++ b/tests/acceptance/fixtures/patches-file-patch-from-web/composer.json @@ -1,19 +1,21 @@ { - "name": "cweagans/composer-patches-test-project", - "description": "Project for use in cweagans/composer-patches acceptance tests.", - "type": "project", - "license": "BSD-2-Clause", - "repositories": [ - { - "type": "path", - "url": "../composer-patches" + "name": "cweagans/composer-patches-test-project", + "description": "Project for use in cweagans/composer-patches acceptance tests.", + "type": "project", + "license": "BSD-2-Clause", + "repositories": [ + { + "type": "path", + "url": "../composer-patches" + } + ], + "require": { + "cweagans/composer-patches": "*@dev", + "drupal/drupal": "~8.2" + }, + "extra": { + "composer-patches": { + "patches-file": "patches.json" + } } - ], - "require": { - "cweagans/composer-patches": "*@dev", - "drupal/drupal": "~8.2" - }, - "extra": { - "patches-file": "patches.json" - } }