Skip to content

Commit 64d7306

Browse files
committed
Issue #3104922 by greg.1.anderson, Mile23, alexpott: Guard against changes to Scaffold Plugin that might cause upgrade problems
(cherry picked from commit 61fa1bf27cbe173b777b345dc2b3f123b6bd5532)
1 parent dca4b12 commit 64d7306

File tree

2 files changed

+50
-16
lines changed

2 files changed

+50
-16
lines changed

Handler.php

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use Composer\Installer\PackageEvent;
88
use Composer\IO\IOInterface;
99
use Composer\Package\PackageInterface;
10-
use Composer\Plugin\CommandEvent;
1110
use Composer\Util\Filesystem;
1211
use Drupal\Composer\Plugin\Scaffold\Operations\OperationData;
1312
use Drupal\Composer\Plugin\Scaffold\Operations\OperationFactory;
@@ -82,14 +81,9 @@ public function __construct(Composer $composer, IOInterface $io) {
8281
}
8382

8483
/**
85-
* Registers post-package events before any 'require' event runs.
86-
*
87-
* This method is called by composer prior to doing a 'require' command.
88-
*
89-
* @param \Composer\Plugin\CommandEvent $event
90-
* The Composer Command event.
84+
* Registers post-package events if the 'require' command was called.
9185
*/
92-
public function beforeRequire(CommandEvent $event) {
86+
public function requireWasCalled() {
9387
// In order to differentiate between post-package events called after
9488
// 'composer require' vs. the same events called at other times, we will
9589
// only install our handler when a 'require' event is detected.

Plugin.php

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,41 @@
2121
*/
2222
class Plugin implements PluginInterface, EventSubscriberInterface, Capable {
2323

24+
/**
25+
* The Composer service.
26+
*
27+
* @var \Composer\Composer
28+
*/
29+
protected $composer;
30+
31+
/**
32+
* Composer's I/O service.
33+
*
34+
* @var \Composer\IO\IOInterface
35+
*/
36+
protected $io;
37+
2438
/**
2539
* The Composer Scaffold handler.
2640
*
2741
* @var \Drupal\Composer\Plugin\Scaffold\Handler
2842
*/
2943
protected $handler;
3044

45+
/**
46+
* Record whether the 'require' command was called.
47+
*
48+
* @param bool
49+
*/
50+
protected $requireWasCalled;
51+
3152
/**
3253
* {@inheritdoc}
3354
*/
3455
public function activate(Composer $composer, IOInterface $io) {
35-
// We use a Handler object to separate the main functionality
36-
// of this plugin from the Composer API. This also avoids some
37-
// debug issues with the plugin being copied on initialisation.
38-
// @see \Composer\Plugin\PluginManager::registerPackage()
39-
$this->handler = new Handler($composer, $io);
56+
$this->composer = $composer;
57+
$this->io = $io;
58+
$this->requireWasCalled = FALSE;
4059
}
4160

4261
/**
@@ -50,6 +69,7 @@ public function getCapabilities() {
5069
* {@inheritdoc}
5170
*/
5271
public static function getSubscribedEvents() {
72+
// Important note: We only instantiate our handler on "post" events.
5373
return [
5474
ScriptEvents::POST_UPDATE_CMD => 'postCmd',
5575
ScriptEvents::POST_INSTALL_CMD => 'postCmd',
@@ -65,7 +85,7 @@ public static function getSubscribedEvents() {
6585
* The Composer event.
6686
*/
6787
public function postCmd(Event $event) {
68-
$this->handler->scaffold();
88+
$this->handler()->scaffold();
6989
}
7090

7191
/**
@@ -75,7 +95,7 @@ public function postCmd(Event $event) {
7595
* Composer package event sent on install/update/remove.
7696
*/
7797
public function postPackage(PackageEvent $event) {
78-
$this->handler->onPostPackageEvent($event);
98+
$this->handler()->onPostPackageEvent($event);
7999
}
80100

81101
/**
@@ -86,8 +106,28 @@ public function postPackage(PackageEvent $event) {
86106
*/
87107
public function onCommand(CommandEvent $event) {
88108
if ($event->getCommandName() == 'require') {
89-
$this->handler->beforeRequire($event);
109+
if ($this->handler) {
110+
throw new \Error('Core Scaffold Plugin handler instantiated too early. See https://www.drupal.org/project/drupal/issues/3104922');
111+
}
112+
$this->requireWasCalled = TRUE;
113+
}
114+
}
115+
116+
/**
117+
* Lazy-instantiate the handler object. It is dangerous to update a Composer
118+
* plugin if it loads any classes prior to the `composer update` operation,
119+
* and later tries to use them in a post-update hook.
120+
*/
121+
protected function handler() {
122+
if (!$this->handler) {
123+
$this->handler = new Handler($this->composer, $this->io);
124+
// On instantiation of our handler, notify it if the 'require' command
125+
// was executed.
126+
if ($this->requireWasCalled) {
127+
$this->handler->requireWasCalled();
128+
}
90129
}
130+
return $this->handler;
91131
}
92132

93133
}

0 commit comments

Comments
 (0)