CustomAutoloaderPlugin.php
6.05 KB
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
<?php //phpcs:ignore WordPress.Files.FileName.NotHyphenatedLowercase
/**
* Custom Autoloader Composer Plugin, hooks into composer events to generate the custom autoloader.
*
* @package automattic/jetpack-autoloader
*/
// phpcs:disable PHPCompatibility.Keywords.NewKeywords.t_useFound
// phpcs:disable PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ns_separatorFound
// phpcs:disable PHPCompatibility.Keywords.NewKeywords.t_namespaceFound
// phpcs:disable WordPress.Files.FileName.NotHyphenatedLowercase
// phpcs:disable WordPress.Files.FileName.InvalidClassFileName
// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
namespace Automattic\Jetpack\Autoloader;
use Composer\Composer;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;
use Composer\Script\Event;
use Composer\Script\ScriptEvents;
/**
* Class CustomAutoloaderPlugin.
*
* @package automattic/jetpack-autoloader
*/
class CustomAutoloaderPlugin implements PluginInterface, EventSubscriberInterface {
/**
* IO object.
*
* @var IOInterface IO object.
*/
private $io;
/**
* Composer object.
*
* @var Composer Composer object.
*/
private $composer;
/**
* Do nothing.
*
* @param Composer $composer Composer object.
* @param IOInterface $io IO object.
*/
public function activate( Composer $composer, IOInterface $io ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
$this->composer = $composer;
$this->io = $io;
}
/**
* Do nothing.
* phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
*
* @param Composer $composer Composer object.
* @param IOInterface $io IO object.
*/
public function deactivate( Composer $composer, IOInterface $io ) {
/*
* Intentionally left empty. This is a PluginInterface method.
* phpcs:enable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
*/
}
/**
* Do nothing.
* phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
*
* @param Composer $composer Composer object.
* @param IOInterface $io IO object.
*/
public function uninstall( Composer $composer, IOInterface $io ) {
/*
* Intentionally left empty. This is a PluginInterface method.
* phpcs:enable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
*/
}
/**
* Tell composer to listen for events and do something with them.
*
* @return array List of subscribed events.
*/
public static function getSubscribedEvents() {
return array(
ScriptEvents::POST_AUTOLOAD_DUMP => 'postAutoloadDump',
);
}
/**
* Generate the custom autolaoder.
*
* @param Event $event Script event object.
*/
public function postAutoloadDump( Event $event ) {
// When the autoloader is not required by the root package we don't want to execute it.
// This prevents unwanted transitive execution that generates unused autoloaders or
// at worst throws fatal executions.
if ( ! $this->isRequiredByRoot() ) {
return;
}
$config = $this->composer->getConfig();
if ( 'vendor' !== $config->raw()['config']['vendor-dir'] ) {
$this->io->writeError( "\n<error>An error occurred while generating the autoloader files:", true );
$this->io->writeError( 'The project\'s composer.json or composer environment set a non-default vendor directory.', true );
$this->io->writeError( 'The default composer vendor directory must be used.</error>', true );
exit();
}
$installationManager = $this->composer->getInstallationManager();
$repoManager = $this->composer->getRepositoryManager();
$localRepo = $repoManager->getLocalRepository();
$package = $this->composer->getPackage();
$optimize = $event->getFlags()['optimize'];
$suffix = $this->determineSuffix();
$generator = new AutoloadGenerator( $this->io );
$generator->dump( $this->composer, $config, $localRepo, $package, $installationManager, 'composer', $optimize, $suffix );
$this->generated = true;
}
/**
* Determine the suffix for the autoloader class.
*
* Reuses an existing suffix from vendor/autoload_packages.php or vendor/autoload.php if possible.
*
* @return string Suffix.
*/
private function determineSuffix() {
$config = $this->composer->getConfig();
$vendorPath = $config->get( 'vendor-dir' );
// Command line.
$suffix = $config->get( 'autoloader-suffix' );
if ( $suffix ) {
return $suffix;
}
// Reuse our own suffix, if any.
if ( is_readable( $vendorPath . '/autoload_packages.php' ) ) {
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
$content = file_get_contents( $vendorPath . '/autoload_packages.php' );
if ( preg_match( '/^namespace Automattic\\\\Jetpack\\\\Autoloader\\\\jp([^;\s]+);/m', $content, $match ) ) {
return $match[1];
}
}
// Reuse Composer's suffix, if any.
if ( is_readable( $vendorPath . '/autoload.php' ) ) {
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
$content = file_get_contents( $vendorPath . '/autoload.php' );
if ( preg_match( '{ComposerAutoloaderInit([^:\s]+)::}', $content, $match ) ) {
return $match[1];
}
}
// Generate a random suffix.
return md5( uniqid( '', true ) );
}
/**
* Checks to see whether or not the root package is the one that required the autoloader.
*
* @return bool
*/
private function isRequiredByRoot() {
$package = $this->composer->getPackage();
$requires = $package->getRequires();
if ( ! is_array( $requires ) ) {
$requires = array();
}
$devRequires = $package->getDevRequires();
if ( ! is_array( $devRequires ) ) {
$devRequires = array();
}
$requires = array_merge( $requires, $devRequires );
if ( empty( $requires ) ) {
$this->io->writeError( "\n<error>The package is not required and this should never happen?</error>", true );
exit();
}
foreach ( $requires as $require ) {
if ( 'automattic/jetpack-autoloader' === $require->getTarget() ) {
return true;
}
}
return false;
}
}