-
Notifications
You must be signed in to change notification settings - Fork 4
/
class-plugin.php
293 lines (255 loc) · 8.18 KB
/
class-plugin.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
<?php
/**
* Altis Core Composer plugin class.
*
* @package altis/core
*/
namespace Altis\Composer;
use Composer\Composer;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\DependencyResolver\Operation\UpdateOperation;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\Installer\InstallerEvent;
use Composer\Installer\PackageEvent;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;
/**
* Altis core composer plugin.
*/
class Plugin implements PluginInterface, EventSubscriberInterface {
/**
* Custom installer instance.
*
* @var Installer
*/
protected $installer;
/**
* Composer instance.
*
* @var Composer
*/
protected $composer;
/**
* IO instance.
*
* @var IOInterface
*/
protected $io;
/**
* Called when the plugin is activated.
*
* @param Composer $composer The composer class.
* @param IOInterface $io The composer disk interface.
*/
public function activate( Composer $composer, IOInterface $io ) {
$this->composer = $composer;
$this->io = $io;
$this->installer = new Override_Installer( $this->io, $this->composer );
$this->composer->getInstallationManager()->addInstaller( $this->installer );
}
/**
* Get the events the plugin subscribed to.
*
* @return array
*/
public static function getSubscribedEvents() {
return [
'init' => 'init',
'pre-operations-exec' => 'pre_operations_exec',
'post-dependencies-solving' => 'post_dependencies_solving',
'post-package-install' => 'post_package_install',
'post-package-update' => 'post_package_install',
];
}
/**
* Register the installer on the `init` hook.
*
* We want to register later than the composer-installers installer
* as the last-added installer takes precedence. This event only runs
* on update (if this plugin is already present), so we have to add it
* in addition to the $this->activate() method.
*/
public function init() {
$this->installer = new Override_Installer( $this->io, $this->composer );
$this->composer->getInstallationManager()->addInstaller( $this->installer );
// If we have a lockfile set the overrides early to handle
// dump-autoload commands correctly.
$lock_file = dirname( $this->composer->getConfig()->get( 'vendor-dir' ) ) . DIRECTORY_SEPARATOR . 'composer.lock';
if ( ! is_readable( $lock_file ) ) {
return;
}
$repo = $this->composer->getLocker()->getLockedRepository( true );
$packages = [];
foreach ( $repo->getPackages() as $package ) {
$packages[ $package->getName() ] = $package;
}
// Set the overrides based on currently known packages.
$overrides = $this->get_all_install_overrides( $packages );
$this->installer->setInstallOverrides( $overrides );
}
/**
* Update install overrides once dependencies have been resolved. (Composer v2)
*
* @param InstallerEvent $event Pre-operations installer event.
* @return void
*/
public function pre_operations_exec( InstallerEvent $event ) : void {
$transaction = $event->getTransaction();
$operations = $transaction->getOperations();
if ( empty( $operations ) ) {
return;
}
// Work out which packages we already have.
$repo = $event->getComposer()->getLocker()->getLockedRepository( $event->isDevMode() );
$packages = [];
foreach ( $repo->getPackages() as $package ) {
$packages[ $package->getName() ] = $package;
}
// Then, resolve the operations we're about to apply.
// In Composer v2, this is when running the initial install step.
$overrides = $this->resolve_packages_composer_v2( $packages, $operations );
$this->installer->setInstallOverrides( $overrides );
}
/**
* Resolve packages after operations for Composer v2
*
* @param array $packages Map of package name => package instance for already installed packages.
* @param \Composer\DependencyResolver\Operation\OperationInterface[] $operations List of operations
* @return string[] List of packages to override.
*/
protected function resolve_packages_composer_v2( array $packages, array $operations ) : array {
foreach ( $operations as $operation ) {
switch ( $operation->getOperationType() ) {
case 'install':
case 'markAliasInstalled':
$package = $operation->getPackage();
$packages[ $package->getName() ] = $package;
break;
case 'update':
$package = $operation->getTargetPackage();
$packages[ $package->getName() ] = $package;
break;
case 'uninstall':
case 'markAliasUninstalled':
$package = $operation->getPackage();
unset( $packages[ $package->getName() ] );
break;
default:
break;
}
}
return $this->get_all_install_overrides( $packages );
}
/**
* Update install overrides once dependencies have been resolved. (Composer v1)
*
* @param InstallerEvent $event Post-solving event.
* @return void
*/
public function post_dependencies_solving( InstallerEvent $event ) : void {
$operations = $event->getOperations();
if ( empty( $operations ) ) {
return;
}
// First, work out which packages we already have.
$repo = $event->getInstalledRepo();
$packages = [];
foreach ( $repo->getPackages() as $package ) {
$packages[ $package->getName() ] = $package;
}
// Then, resolve the operations we're about to apply.
foreach ( $operations as $operation ) {
switch ( $operation->getJobType() ) {
case 'install':
case 'markAliasInstalled':
$package = $operation->getPackage();
$packages[ $package->getName() ] = $package;
break;
case 'update':
$package = $operation->getTargetPackage();
$packages[ $package->getName() ] = $package;
break;
case 'uninstall':
case 'markAliasUninstalled':
$package = $operation->getPackage();
unset( $packages[ $package->getName() ] );
break;
default:
break;
}
}
$overrides = $this->get_all_install_overrides( $packages );
$this->installer->setInstallOverrides( $overrides );
}
/**
* Handle first install of the altis/core package.
*
* @param PackageEvent $event Package installation event.
* @return void
*/
public function post_package_install( PackageEvent $event ) : void {
// See if we just got installed.
$operation = $event->getOperation();
if ( ! $operation instanceof InstallOperation && ! $operation instanceof UpdateOperation ) {
return;
}
$package = $operation instanceof UpdateOperation ? $operation->getTargetPackage() : $operation->getPackage();
if ( $package->getName() !== 'altis/core' ) {
return;
}
// Just Installed! 👰🤵
// This means we won't have caught the dependency resolution event,
// so we need to do so now. PackageEvent subclasses InstallerEvent
// in Composer v1, but not in v2.
if ( $event instanceof InstallerEvent ) {
// Composer v1.
$this->post_dependencies_solving( $event );
return;
}
$operations = $event->getOperations();
if ( empty( $operations ) ) {
return;
}
// Work out which packages we already have.
$repo = $event->getComposer()->getLocker()->getLockedRepository( $event->isDevMode() );
$packages = [];
foreach ( $repo->getPackages() as $package ) {
$packages[ $package->getName() ] = $package;
}
$overrides = $this->resolve_packages_composer_v2( $packages, $operations );
$this->installer->setInstallOverrides( $overrides );
}
/**
* Gets all overridden packages from all extra.altis.install-overrides entries
*
* @param \Composer\Package\PackageInterface[] $packages All packages being installed.
* @return string[]
*/
protected function get_all_install_overrides( $packages ) : array {
$overridden = [];
foreach ( $packages as $package ) {
$extra = $package->getExtra();
if ( ! isset( $extra['altis'] ) || ! isset( $extra['altis']['install-overrides'] ) ) {
continue;
}
$overridden = array_merge( $overridden, $extra['altis']['install-overrides'] );
}
return $overridden;
}
/**
* {@inheritDoc}
*
* @param Composer $composer The composer class.
* @param IOInterface $io The composer disk interface.
*/
public function deactivate( Composer $composer, IOInterface $io ) {
}
/**
* {@inheritDoc}
*
* @param Composer $composer The composer class.
* @param IOInterface $io The composer disk interface.
*/
public function uninstall( Composer $composer, IOInterface $io ) {
}
}