14
14
use Composer \Composer ;
15
15
use Composer \EventDispatcher \EventSubscriberInterface ;
16
16
use Composer \IO \IOInterface ;
17
- use Composer \Package \Package ;
18
17
use Composer \Package \PackageInterface ;
19
18
use Composer \Package \RootPackageInterface ;
20
19
use Composer \Plugin \PluginInterface ;
21
20
use Composer \Script \ScriptEvents ;
22
21
use Composer \Util \Filesystem ;
23
- use RuntimeException ;
24
22
23
+ /**
24
+ * @phpstan-import-type AutoloadRules from PackageInterface
25
+ */
25
26
class ExcludeFilePlugin implements
26
27
PluginInterface,
27
28
EventSubscriberInterface
@@ -93,53 +94,46 @@ public static function getSubscribedEvents(): array
93
94
*/
94
95
public function parseAutoloads (): void
95
96
{
96
- $ composer = $ this ->composer ;
97
-
98
- $ package = $ composer ->getPackage ();
97
+ $ rootPackage = $ this ->composer ->getPackage ();
99
98
100
- $ excludedFiles = $ this ->parseExcludedFiles ( $ this -> getExcludedFiles ($ package ) );
101
- if (! $ excludedFiles ) {
99
+ $ excludedFiles = $ this ->getExcludedFiles ($ rootPackage );
100
+ if ($ excludedFiles-> isEmpty () ) {
102
101
return ;
103
102
}
104
103
105
- $ excludedFiles = \array_fill_keys ($ excludedFiles , true );
106
-
107
- $ generator = $ composer ->getAutoloadGenerator ();
108
- $ packages = $ composer ->getRepositoryManager ()->getLocalRepository ()->getCanonicalPackages ();
109
- $ packageMap = $ generator ->buildPackageMap ($ composer ->getInstallationManager (), $ package , $ packages );
104
+ $ generator = $ this ->composer ->getAutoloadGenerator ();
105
+ $ packageMap = $ generator ->buildPackageMap (
106
+ $ this ->composer ->getInstallationManager (),
107
+ $ rootPackage ,
108
+ $ this ->composer ->getRepositoryManager ()->getLocalRepository ()->getCanonicalPackages ()
109
+ );
110
110
111
- $ this ->filterAutoloads ($ packageMap , $ package , $ excludedFiles );
111
+ $ this ->filterPackageMapAutoloads ($ packageMap , $ rootPackage , $ excludedFiles );
112
112
}
113
113
114
114
/**
115
- * Alters packages to exclude files required in "autoload.files" by
116
- * "extra.exclude-from-files".
115
+ * Alters packages to exclude files required in "autoload.files"
116
+ * by "extra.exclude-from-files".
117
117
*
118
- * @param array<int, array{PackageInterface, ?string}> $packageMap
119
- * List of packages and their installation paths.
120
- * @param RootPackageInterface $rootPackage
121
- * Root package instance.
122
- * @param array<string, true> $excludedFiles
123
- * Map of files to exclude from the "files" autoload mechanism.
118
+ * @param array{PackageInterface, ?string}[] $packageMap List of packages
119
+ * and their installation paths.
120
+ * @param RootPackageInterface $rootPackage Root package instance.
121
+ * @param Paths $excludedFiles Collection of Path instances
122
+ * to exclude from the "files" autoload mechanism.
124
123
* @return void
125
124
*/
126
- private function filterAutoloads (
125
+ private function filterPackageMapAutoloads (
127
126
array $ packageMap ,
128
127
RootPackageInterface $ rootPackage ,
129
- array $ excludedFiles
128
+ Paths $ excludedFiles
130
129
): void {
131
130
foreach ($ packageMap as [ $ package , $ installPath ]) {
132
- // Skip root package
131
+ // Skip root package.
133
132
if ($ package === $ rootPackage ) {
134
133
continue ;
135
134
}
136
135
137
- // Skip immutable package
138
- if (!($ package instanceof Package)) {
139
- continue ;
140
- }
141
-
142
- // Skip packages that are not installed
136
+ // Skip package if nothing is installed.
143
137
if (null === $ installPath ) {
144
138
continue ;
145
139
}
@@ -152,23 +146,29 @@ private function filterAutoloads(
152
146
* Alters a package to exclude files required in "autoload.files" by
153
147
* "extra.exclude-from-files".
154
148
*
155
- * @param Package $package The package to filter.
156
- * @param string $installPath The installation path of $package.
157
- * @param array<string, true> $excludedFiles Map of files to exclude from
158
- * the "files" autoload mechanism.
149
+ * @param PackageInterface $package The package to filter.
150
+ * @param string $installPath The installation path of $package.
151
+ * @param Paths $excludedFiles Collection of Path instances to exclude
152
+ * from the "files" autoload mechanism.
159
153
* @return void
160
154
*/
161
155
private function filterPackageAutoloads (
162
- Package $ package ,
156
+ PackageInterface $ package ,
163
157
string $ installPath ,
164
- array $ excludedFiles
158
+ Paths $ excludedFiles
165
159
): void {
160
+ // Skip package if immutable.
161
+ if (!\method_exists ($ package , 'setAutoload ' )) {
162
+ return ;
163
+ }
164
+
166
165
$ type = self ::INCLUDE_FILES_PROPERTY ;
167
166
167
+ /** @var array<string, string[]> */
168
168
$ autoload = $ package ->getAutoload ();
169
169
170
170
// Skip misconfigured packages
171
- if (! isset ($ autoload [$ type ]) || !\is_array ($ autoload [$ type ])) {
171
+ if (empty ($ autoload [$ type ]) || !\is_array ($ autoload [$ type ])) {
172
172
return ;
173
173
}
174
174
@@ -178,79 +178,50 @@ private function filterPackageAutoloads(
178
178
179
179
$ filtered = false ;
180
180
181
- foreach ($ autoload [$ type ] as $ key => $ path ) {
182
- if ($ package ->getTargetDir () && !\is_readable ($ installPath .'/ ' .$ path )) {
183
- // add target-dir from file paths that don't have it
184
- $ path = $ package ->getTargetDir () . '/ ' . $ path ;
181
+ foreach ($ autoload [$ type ] as $ index => $ localPath ) {
182
+ if ($ package ->getTargetDir () && !\is_readable ($ installPath .'/ ' .$ localPath )) {
183
+ // Add ' target-dir' from file paths that don't have it
184
+ $ localPath = $ package ->getTargetDir () . '/ ' . $ localPath ;
185
185
}
186
186
187
- $ resolvedPath = $ installPath . '/ ' . $ path ;
188
- $ resolvedPath = \strtr ($ resolvedPath , '\\' , '/ ' );
187
+ $ absolutePath = $ installPath . '/ ' . $ localPath ;
188
+ $ absolutePath = \strtr ($ absolutePath , '\\' , '/ ' );
189
189
190
- if (isset ( $ excludedFiles[ $ resolvedPath ] )) {
190
+ if ($ excludedFiles-> isMatch ( $ absolutePath )) {
191
191
$ filtered = true ;
192
- unset($ autoload [$ type ][$ key ]);
192
+ unset($ autoload [$ type ][$ index ]);
193
193
}
194
194
}
195
195
196
196
if ($ filtered ) {
197
+ /**
198
+ * @disregard P1013 Package method existance validated earlier.
199
+ * {@see https://github.com/bmewburn/vscode-intelephense/issues/952}.
200
+ */
197
201
$ package ->setAutoload ($ autoload );
198
202
}
199
203
}
200
204
201
205
/**
202
- * Gets a list files the root package wants to exclude.
206
+ * Gets a parsed list of files the given package wants to exclude.
203
207
*
204
208
* @param PackageInterface $package Root package instance.
205
- * @return string[] Retuns the list of excluded files .
209
+ * @return Paths Retuns a collection of Path instances .
206
210
*/
207
- private function getExcludedFiles (PackageInterface $ package ): array
211
+ private function getExcludedFiles (PackageInterface $ package ): Paths
208
212
{
209
213
$ type = self ::EXCLUDE_FILES_PROPERTY ;
210
214
211
215
$ extra = $ package ->getExtra ();
212
216
213
- if (isset ($ extra [$ type ]) && \is_array ($ extra [$ type ])) {
214
- return $ extra [$ type ];
215
- }
216
-
217
- return [];
218
- }
219
-
220
- /**
221
- * Prepends the vendor directory to each path in "extra.exclude-from-files".
222
- *
223
- * @param string[] $paths Array of paths relative to the composer manifest.
224
- * @throws RuntimeException If the 'vendor-dir' path is unavailable.
225
- * @return string[] Retuns the array of paths, prepended with the vendor directory.
226
- */
227
- private function parseExcludedFiles (array $ paths ): array
228
- {
229
- if (!$ paths ) {
230
- return $ paths ;
231
- }
232
-
233
- $ config = $ this ->composer ->getConfig ();
234
- $ vendorDir = $ config ->get ('vendor-dir ' );
235
- if (!$ vendorDir ) {
236
- throw new RuntimeException (
237
- 'Invalid value for \'vendor-dir \'. Expected string '
238
- );
239
- }
240
-
241
- $ filesystem = new Filesystem ();
242
- // Do not remove double realpath() calls.
243
- // Fixes failing Windows realpath() implementation.
244
- // See https://bugs.php.net/bug.php?id=72738
245
- /** @var string */
246
- $ vendorPath = \realpath (\realpath ($ vendorDir ));
247
- $ vendorPath = $ filesystem ->normalizePath ($ vendorPath );
248
-
249
- foreach ($ paths as &$ path ) {
250
- $ path = \preg_replace ('{/+} ' , '/ ' , \trim (\strtr ($ path , '\\' , '/ ' ), '/ ' ));
251
- $ path = $ vendorPath . '/ ' . $ path ;
217
+ if (empty ($ extra [$ type ]) || !\is_array ($ extra [$ type ])) {
218
+ return new Paths ;
252
219
}
253
220
254
- return $ paths ;
221
+ return Paths::create (
222
+ new Filesystem (),
223
+ $ this ->composer ->getConfig (),
224
+ $ extra [$ type ]
225
+ );
255
226
}
256
227
}
0 commit comments