Skip to content

Commit 81bb220

Browse files
committed
Scan only included paths
1 parent 40f5a3e commit 81bb220

File tree

9 files changed

+101
-219
lines changed

9 files changed

+101
-219
lines changed

src/ClassAttributeCollector.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use Composer\IO\IOInterface;
77
use ReflectionAttribute;
88
use ReflectionClass;
9-
use ReflectionException;
9+
use Throwable;
1010

1111
/**
1212
* @internal
@@ -28,11 +28,16 @@ public function __construct(
2828
* }
2929
* Where `0` is an array of class attributes, `1` is an array of method attributes,
3030
* and `2` is an array of property attributes.
31-
* @throws ReflectionException
3231
*/
3332
public function collectAttributes(string $class): array
3433
{
35-
$classReflection = new ReflectionClass($class);
34+
try {
35+
$classReflection = new ReflectionClass($class);
36+
} catch (Throwable $e) { // @phpstan-ignore-line
37+
$this->io->error("Unable to collection attribute from class $class: {$e->getMessage()}");
38+
39+
return [ [], [], [] ];
40+
}
3641

3742
if (self::isAttribute($classReflection)) {
3843
return [ [], [], [] ];

src/Config.php

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
use InvalidArgumentException;
88
use RuntimeException;
99

10+
use function array_map;
1011
use function dirname;
12+
use function implode;
1113
use function is_string;
14+
use function preg_quote;
1215
use function realpath;
1316
use function str_ends_with;
1417
use function str_starts_with;
@@ -55,25 +58,46 @@ public static function from(PartialComposer $composer): self
5558
$exclude = self::expandPaths($extra[self::EXTRA_EXCLUDE] ?? [], $vendorDir, $rootDir);
5659

5760
return new self(
61+
$vendorDir,
5862
attributesFile: "$vendorDir/attributes.php",
5963
include: $include,
6064
exclude: $exclude,
6165
);
6266
}
6367

68+
/**
69+
* @readonly
70+
* @var non-empty-string|null
71+
*/
72+
public ?string $excludeRegExp;
73+
6474
/**
6575
* @param non-empty-string $attributesFile
6676
* Absolute path to the `attributes.php` file.
67-
* @param string[] $include
77+
* @param non-empty-string[] $include
6878
* Paths that should be included to attributes collection.
69-
* @param string[] $exclude
79+
* @param non-empty-string[] $exclude
7080
* Paths that should be excluded from attributes collection.
7181
*/
7282
public function __construct(
83+
public string $vendorDir,
7384
public string $attributesFile,
7485
public array $include,
7586
public array $exclude,
7687
) {
88+
$this->excludeRegExp = count($exclude) ? self::compileExclude($this->exclude) : null;
89+
}
90+
91+
/**
92+
* @param non-empty-string[] $exclude
93+
*
94+
* @return non-empty-string
95+
*/
96+
private static function compileExclude(array $exclude): string
97+
{
98+
$regexp = implode('|', array_map(fn (string $path) => preg_quote($path), $exclude));
99+
100+
return "($regexp)";
77101
}
78102

79103
/**

src/FileDatastore.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public function __construct(
3838

3939
public function get(string $key): array
4040
{
41-
$filename = $this->dir . DIRECTORY_SEPARATOR . $key;
41+
$filename = $this->formatFilename($key);
4242

4343
if (!file_exists($filename)) {
4444
return [];
@@ -49,7 +49,7 @@ public function get(string $key): array
4949

5050
public function set(string $key, array $data): void
5151
{
52-
$filename = $this->dir . DIRECTORY_SEPARATOR . $key;
52+
$filename = $this->formatFilename($key);
5353

5454
file_put_contents($filename, serialize($data));
5555
}
@@ -85,4 +85,12 @@ private function safeGet(string $filename): array
8585

8686
return $ar;
8787
}
88+
89+
private function formatFilename(string $key): string
90+
{
91+
$major = Plugin::VERSION_MAJOR;
92+
$minor = Plugin::VERSION_MINOR;
93+
94+
return $this->dir . DIRECTORY_SEPARATOR . "v$major-$minor-$key";
95+
}
8896
}

src/Filter/PathFilter.php

Lines changed: 0 additions & 46 deletions
This file was deleted.

src/Plugin.php

Lines changed: 30 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,12 @@
88
use Composer\Plugin\PluginInterface;
99
use Composer\Script\Event;
1010
use Composer\Util\Platform;
11+
1112
use olvlvl\ComposerAttributeCollector\Filter\ContentFilter;
1213
use olvlvl\ComposerAttributeCollector\Filter\InterfaceFilter;
13-
use olvlvl\ComposerAttributeCollector\Filter\PathFilter;
14-
use ReflectionException;
1514

1615
use function file_put_contents;
1716
use function microtime;
18-
use function spl_autoload_register;
1917
use function sprintf;
2018

2119
use const DIRECTORY_SEPARATOR;
@@ -26,6 +24,8 @@
2624
final class Plugin implements PluginInterface, EventSubscriberInterface
2725
{
2826
public const CACHE_DIR = '.composer-attribute-collector';
27+
public const VERSION_MAJOR = 2;
28+
public const VERSION_MINOR = 0;
2929

3030
/**
3131
* @uses onPostAutoloadDump
@@ -66,62 +66,62 @@ public static function onPostAutoloadDump(Event $event): void
6666
$config = Config::from($composer);
6767
$io = $event->getIO();
6868

69+
require_once $config->vendorDir . "/autoload.php";
70+
6971
$start = microtime(true);
7072
$io->write('<info>Generating attributes file</info>');
71-
self::dump($event->getComposer(), $config, $io);
73+
self::dump($config, $io);
7274
$elapsed = self::renderElapsedTime($start);
7375
$io->write("<info>Generated attributes file in $elapsed</info>");
7476
}
7577

76-
/**
77-
* @throws ReflectionException
78-
*/
7978
public static function dump(
80-
Composer $composer,
8179
Config $config,
82-
IOInterface $io,
83-
AutoloadsBuilder $autoloadsBuilder = null,
84-
ClassMapBuilder $classMapBuilder = null
80+
IOInterface $io
8581
): void {
82+
//
83+
// Scan include paths
84+
//
85+
$start = microtime(true);
8686
$datastore = self::buildDefaultDatastore($io);
87-
$autoloadsBuilder ??= new AutoloadsBuilder();
8887
$classMapGenerator = new MemoizeClassMapGenerator($datastore, $io);
89-
$classMapBuilder ??= new ClassMapBuilder($classMapGenerator);
90-
$classMapFilter = new MemoizeClassMapFilter($datastore, $io);
91-
$attributeCollector = new MemoizeAttributeCollector(new ClassAttributeCollector($io), $datastore, $io);
92-
93-
$start = microtime(true);
94-
$autoloads = $autoloadsBuilder->buildAutoloads($composer);
95-
$elapsed = self::renderElapsedTime($start);
96-
$io->debug("Generating attributes file: built autoloads in $elapsed");
97-
98-
$start = microtime(true);
99-
$classMap = $classMapBuilder->buildClassMap($autoloads);
88+
foreach ($config->include as $include) {
89+
$classMapGenerator->scanPaths($include, $config->excludeRegExp);
90+
}
91+
$classMap = $classMapGenerator->getMap();
10092
$elapsed = self::renderElapsedTime($start);
101-
$io->debug("Generating attributes file: built class map in $elapsed");
102-
103-
self::setupAutoload($classMap);
93+
$io->debug("Generating attributes file: scanned paths in $elapsed");
10494

95+
//
96+
// Filter the class map
97+
//
10598
$start = microtime(true);
106-
$filter = self::buildFileFilter($config);
99+
$classMapFilter = new MemoizeClassMapFilter($datastore, $io);
100+
$filter = self::buildFileFilter();
107101
$classMap = $classMapFilter->filter(
108102
$classMap,
109103
fn (string $class, string $filepath): bool => $filter->filter($filepath, $class, $io)
110104
);
111105
$elapsed = self::renderElapsedTime($start);
112106
$io->debug("Generating attributes file: filtered class map in $elapsed");
113107

108+
//
109+
// Collect attributes
110+
//
114111
$start = microtime(true);
112+
$attributeCollector = new MemoizeAttributeCollector(new ClassAttributeCollector($io), $datastore, $io);
115113
$collection = $attributeCollector->collectAttributes($classMap);
116114
$elapsed = self::renderElapsedTime($start);
117115
$io->debug("Generating attributes file: collected attributes in $elapsed");
118116

117+
//
118+
// Render attributes
119+
//
119120
$start = microtime(true);
120121
$code = self::render($collection);
122+
file_put_contents($config->attributesFile, $code);
121123
$elapsed = self::renderElapsedTime($start);
122124
$io->debug("Generating attributes file: rendered code in $elapsed");
123-
124-
file_put_contents($config->attributesFile, $code);
125125
}
126126

127127
private static function buildDefaultDatastore(IOInterface $io): Datastore
@@ -137,27 +137,9 @@ private static function renderElapsedTime(float $start): string
137137
{
138138
return sprintf("%.03f ms", (microtime(true) - $start) * 1000);
139139
}
140-
141-
/**
142-
* @param array<class-string, non-empty-string> $classMap
143-
*/
144-
private static function setupAutoload(array $classMap): void
145-
{
146-
spl_autoload_register(static function (string $class) use ($classMap): void {
147-
$file = $classMap[$class] ?? null;
148-
if ($file) {
149-
require_once $file;
150-
}
151-
});
152-
}
153-
154-
private static function buildFileFilter(Config $config): Filter
140+
private static function buildFileFilter(): Filter
155141
{
156142
return new Filter\Chain([
157-
new PathFilter(
158-
include: $config->include,
159-
exclude: $config->exclude
160-
),
161143
new ContentFilter(),
162144
new InterfaceFilter()
163145
]);

tests/ConfigTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public function testFrom(): void
4747
$composer->setPackage($package);
4848

4949
$expected = new Config(
50+
vendorDir: "$cwd/vendor",
5051
attributesFile: "$cwd/vendor/attributes.php",
5152
include: [
5253
"$cwd/tests",

tests/FileDatastoreTest.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Composer\IO\IOInterface;
66
use olvlvl\ComposerAttributeCollector\FileDatastore;
7+
use olvlvl\ComposerAttributeCollector\Plugin;
78
use PHPUnit\Framework\MockObject\MockObject;
89
use PHPUnit\Framework\TestCase;
910

@@ -80,6 +81,8 @@ public function testUnserializeWithMissingClass(): void
8081

8182
private static function write(string $str): void
8283
{
83-
file_put_contents(self::DIR . self::KEY, $str);
84+
$filename = self::DIR . 'v' . Plugin::VERSION_MAJOR . '-' . Plugin::VERSION_MINOR . '-' . self::KEY;
85+
86+
file_put_contents($filename, $str);
8487
}
8588
}

0 commit comments

Comments
 (0)