From 326308fcf7bd24eae5cdd672c6eeb56841fcf8e2 Mon Sep 17 00:00:00 2001 From: Matthias Glaub Date: Fri, 12 Oct 2018 00:10:46 +0200 Subject: [PATCH 1/3] first draft to guess dependencies from composer's autoloader --- CHANGELOG.md | 1 + .../Cli/CheckCommand.php | 2 ++ .../DependencyGuesser/DependencyGuesser.php | 5 +++ .../GuessFromComposerAutoloader.php | 35 +++++++++++++++++++ .../GuessFromComposerAutoloaderTest.php | 33 +++++++++++++++++ 5 files changed, 76 insertions(+) create mode 100644 src/ComposerRequireChecker/DependencyGuesser/GuessFromComposerAutoloader.php create mode 100644 test/ComposerRequireCheckerTest/DependencyGuesser/GuessFromComposerAutoloaderTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 84d10832..489779cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [unreleased] ### Added +- guess dependencies from composer's autoloader ### Changed diff --git a/src/ComposerRequireChecker/Cli/CheckCommand.php b/src/ComposerRequireChecker/Cli/CheckCommand.php index c171ff6d..b519e696 100644 --- a/src/ComposerRequireChecker/Cli/CheckCommand.php +++ b/src/ComposerRequireChecker/Cli/CheckCommand.php @@ -7,6 +7,7 @@ use ComposerRequireChecker\DefinedSymbolsLocator\LocateDefinedSymbolsFromASTRoots; use ComposerRequireChecker\DefinedSymbolsLocator\LocateDefinedSymbolsFromExtensions; use ComposerRequireChecker\DependencyGuesser\DependencyGuesser; +use ComposerRequireChecker\DependencyGuesser\GuessFromComposerAutoloader; use ComposerRequireChecker\FileLocator\LocateComposerPackageDirectDependenciesSourceFiles; use ComposerRequireChecker\FileLocator\LocateComposerPackageSourceFiles; use ComposerRequireChecker\FileLocator\LocateFilesByGlobPattern; @@ -108,6 +109,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $table = new Table($output); $table->setHeaders(['unknown symbol', 'guessed dependency']); $guesser = new DependencyGuesser(); + $guesser->addGuesser(new GuessFromComposerAutoloader($composerJson)); foreach ($unknownSymbols as $unknownSymbol) { $guessedDependencies = []; foreach ($guesser($unknownSymbol) as $guessedDependency) { diff --git a/src/ComposerRequireChecker/DependencyGuesser/DependencyGuesser.php b/src/ComposerRequireChecker/DependencyGuesser/DependencyGuesser.php index deb57b1c..b144017c 100644 --- a/src/ComposerRequireChecker/DependencyGuesser/DependencyGuesser.php +++ b/src/ComposerRequireChecker/DependencyGuesser/DependencyGuesser.php @@ -15,6 +15,11 @@ public function __construct() $this->guessers[] = new GuessFromLoadedExtensions(); } + public function addGuesser(GuesserInterface $guesser): void + { + $this->guessers[] = $guesser; + } + public function __invoke($symbolName): \Generator { foreach ($this->guessers as $guesser) { diff --git a/src/ComposerRequireChecker/DependencyGuesser/GuessFromComposerAutoloader.php b/src/ComposerRequireChecker/DependencyGuesser/GuessFromComposerAutoloader.php new file mode 100644 index 00000000..618a36a5 --- /dev/null +++ b/src/ComposerRequireChecker/DependencyGuesser/GuessFromComposerAutoloader.php @@ -0,0 +1,35 @@ +configVendorDir = dirname($composerJsonPath) . '/' . ($composerJson['config']['vendor-dir'] ?? 'vendor'); + $this->composerAutoloader = include $this->configVendorDir . '/autoload.php'; + } + + public function __invoke(string $symbolName): \Generator + { + $fullFileName = $this->composerAutoloader->findFile(ltrim($symbolName, '\\/ ')); + if ($fullFileName) { + $fileName = ltrim(substr(realpath($fullFileName), strlen($this->configVendorDir)), '\\/'); + $packageName = preg_replace('/^([^\/]+\/[^\/]+).*/', '$1', $fileName); + yield $packageName; + } + } + +} diff --git a/test/ComposerRequireCheckerTest/DependencyGuesser/GuessFromComposerAutoloaderTest.php b/test/ComposerRequireCheckerTest/DependencyGuesser/GuessFromComposerAutoloaderTest.php new file mode 100644 index 00000000..d0201b14 --- /dev/null +++ b/test/ComposerRequireCheckerTest/DependencyGuesser/GuessFromComposerAutoloaderTest.php @@ -0,0 +1,33 @@ +guesser = new GuessFromComposerAutoloader($dir . '/composer.json'); + } + + public function testClassWillBeFound() + { + $quessedDependencies = $this->guesser->__invoke(ParserFactory::class); + $guessedDependencies = iterator_to_array($quessedDependencies); + + $this->assertCount(1, $guessedDependencies); + $this->assertContains('nikic/php-parser', $guessedDependencies); + } +} From 266391fccc0018d82f7a2e5691ae99ea6168cc78 Mon Sep 17 00:00:00 2001 From: Matthias Glaub Date: Fri, 12 Oct 2018 00:33:56 +0200 Subject: [PATCH 2/3] remove additional method in favour of variable parameters in constructor --- src/ComposerRequireChecker/Cli/CheckCommand.php | 3 +-- .../DependencyGuesser/DependencyGuesser.php | 10 ++++------ .../GuessFromComposerAutoloaderTest.php | 6 +++--- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/ComposerRequireChecker/Cli/CheckCommand.php b/src/ComposerRequireChecker/Cli/CheckCommand.php index b519e696..5fa7a9f1 100644 --- a/src/ComposerRequireChecker/Cli/CheckCommand.php +++ b/src/ComposerRequireChecker/Cli/CheckCommand.php @@ -108,8 +108,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln("The following unknown symbols were found:"); $table = new Table($output); $table->setHeaders(['unknown symbol', 'guessed dependency']); - $guesser = new DependencyGuesser(); - $guesser->addGuesser(new GuessFromComposerAutoloader($composerJson)); + $guesser = new DependencyGuesser(new GuessFromComposerAutoloader($composerJson)); foreach ($unknownSymbols as $unknownSymbol) { $guessedDependencies = []; foreach ($guesser($unknownSymbol) as $guessedDependency) { diff --git a/src/ComposerRequireChecker/DependencyGuesser/DependencyGuesser.php b/src/ComposerRequireChecker/DependencyGuesser/DependencyGuesser.php index b144017c..68a4fa76 100644 --- a/src/ComposerRequireChecker/DependencyGuesser/DependencyGuesser.php +++ b/src/ComposerRequireChecker/DependencyGuesser/DependencyGuesser.php @@ -10,14 +10,12 @@ class DependencyGuesser */ private $guessers = []; - public function __construct() + public function __construct(GuesserInterface ...$guessers) { $this->guessers[] = new GuessFromLoadedExtensions(); - } - - public function addGuesser(GuesserInterface $guesser): void - { - $this->guessers[] = $guesser; + foreach ($guessers as $guesser) { + $this->guessers[] = $guesser; + } } public function __invoke($symbolName): \Generator diff --git a/test/ComposerRequireCheckerTest/DependencyGuesser/GuessFromComposerAutoloaderTest.php b/test/ComposerRequireCheckerTest/DependencyGuesser/GuessFromComposerAutoloaderTest.php index d0201b14..a8e737f8 100644 --- a/test/ComposerRequireCheckerTest/DependencyGuesser/GuessFromComposerAutoloaderTest.php +++ b/test/ComposerRequireCheckerTest/DependencyGuesser/GuessFromComposerAutoloaderTest.php @@ -3,6 +3,7 @@ namespace ComposerRequireCheckerTest\DependencyGuesser; +use ComposerRequireChecker\DependencyGuesser\DependencyGuesser; use ComposerRequireChecker\DependencyGuesser\GuessFromComposerAutoloader; use PhpParser\ParserFactory; use PHPUnit\Framework\TestCase; @@ -11,15 +12,14 @@ class GuessFromComposerAutoloaderTest extends TestCase { /** - * @var GuessFromComposerAutoloader + * @var DependencyGuesser */ private $guesser; public function setUp() { - parent::setUp(); $dir = dirname(__DIR__, 3); - $this->guesser = new GuessFromComposerAutoloader($dir . '/composer.json'); + $this->guesser = new DependencyGuesser(new GuessFromComposerAutoloader($dir . '/composer.json')); } public function testClassWillBeFound() From dbe33ebf86ef7daa404bf3a45ed176662d374a90 Mon Sep 17 00:00:00 2001 From: Matthias Glaub Date: Fri, 12 Oct 2018 10:57:19 +0200 Subject: [PATCH 3/3] fixes path detection on windows --- .../DependencyGuesser/GuessFromComposerAutoloader.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ComposerRequireChecker/DependencyGuesser/GuessFromComposerAutoloader.php b/src/ComposerRequireChecker/DependencyGuesser/GuessFromComposerAutoloader.php index 618a36a5..bfb575f0 100644 --- a/src/ComposerRequireChecker/DependencyGuesser/GuessFromComposerAutoloader.php +++ b/src/ComposerRequireChecker/DependencyGuesser/GuessFromComposerAutoloader.php @@ -18,7 +18,7 @@ class GuessFromComposerAutoloader implements GuesserInterface public function __construct(string $composerJsonPath) { $composerJson = json_decode(file_get_contents($composerJsonPath), true); - $this->configVendorDir = dirname($composerJsonPath) . '/' . ($composerJson['config']['vendor-dir'] ?? 'vendor'); + $this->configVendorDir = $this->normalizePath(dirname($composerJsonPath) . '/' . ($composerJson['config']['vendor-dir'] ?? 'vendor')); $this->composerAutoloader = include $this->configVendorDir . '/autoload.php'; } @@ -26,10 +26,15 @@ public function __invoke(string $symbolName): \Generator { $fullFileName = $this->composerAutoloader->findFile(ltrim($symbolName, '\\/ ')); if ($fullFileName) { - $fileName = ltrim(substr(realpath($fullFileName), strlen($this->configVendorDir)), '\\/'); + $fileName = $this->normalizePath(ltrim(substr(realpath($fullFileName), strlen($this->configVendorDir)), '\\/')); $packageName = preg_replace('/^([^\/]+\/[^\/]+).*/', '$1', $fileName); yield $packageName; } } + private function normalizePath(string $path): string + { + return str_replace('\\', '/', $path); + } + }