From 4d6d2d1368caee4603c118c6f86a29d3bb77771e Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Wed, 4 Sep 2024 08:18:02 +0200 Subject: [PATCH] Fix case where installed path is symlink One can install packages from a local path via composers repositories type "path". Those are typically symlinks which were not resolved. We therefore add a realpath() call, but falling back to old behavior if it didn't resolve. That way we keep independent of realpath() as requested by the inline comment. Resolves: https://github.com/phpactor/phpactor/issues/2727 --- lib/Adapter/Composer/ComposerFileToClass.php | 8 ++++---- .../Composer/ComposerFileToClassTest.php | 9 +++++++++ .../composers/psr4-symlinked-project.json | 18 ++++++++++++++++++ .../project/symlinked-package/Class.php | 7 +++++++ .../project/symlinked-package/composer.json | 16 ++++++++++++++++ 5 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 tests/Integration/Composer/composers/psr4-symlinked-project.json create mode 100644 tests/Integration/Composer/project/symlinked-package/Class.php create mode 100644 tests/Integration/Composer/project/symlinked-package/composer.json diff --git a/lib/Adapter/Composer/ComposerFileToClass.php b/lib/Adapter/Composer/ComposerFileToClass.php index f688627c..9fdb6f10 100644 --- a/lib/Adapter/Composer/ComposerFileToClass.php +++ b/lib/Adapter/Composer/ComposerFileToClass.php @@ -77,11 +77,11 @@ private function populateCandidates(FilePath $filePath, array $prefixes) $pathPrefixes = (array) $pathPrefixes; // remove any relativeness from the paths - // - // TODO: realpath will return void if the path does not exist - // we should not depend on the file path existing. + // we should not depend on the file path existing. $pathPrefixes = array_map(function ($pathPrefix) { - return Path::canonicalize($pathPrefix); + $canonicalizedPath = Path::canonicalize($pathPrefix); + $realPath = realpath($canonicalizedPath); + return $realPath ?: $canonicalizedPath; }, $pathPrefixes); foreach ($pathPrefixes as $pathPrefix) { diff --git a/tests/Integration/Composer/ComposerFileToClassTest.php b/tests/Integration/Composer/ComposerFileToClassTest.php index 6f9e9287..a36582c5 100644 --- a/tests/Integration/Composer/ComposerFileToClassTest.php +++ b/tests/Integration/Composer/ComposerFileToClassTest.php @@ -35,6 +35,15 @@ public function testPsr4WithRelativePathComponents(): void $this->assertFilePathToClassName('/psr4/Foo/../Foo/Class.php', ['Acme\\Test\\Foo\\Class']); } + /** + * @testdox PSR-4 file with symlinked path components + */ + public function testPsr4Symlinked(): void + { + $this->loadExample('psr4-symlinked-project.json'); + $this->assertFilePathToClassName('/symlinked-package/Class.php', ['Acme\\Test\\Class']); + } + /** * @testdox PSR-4 multiple matching prefixes */ diff --git a/tests/Integration/Composer/composers/psr4-symlinked-project.json b/tests/Integration/Composer/composers/psr4-symlinked-project.json new file mode 100644 index 00000000..6b1daa1c --- /dev/null +++ b/tests/Integration/Composer/composers/psr4-symlinked-project.json @@ -0,0 +1,18 @@ +{ + "name": "dantleech/basic", + "authors": [ + { + "name": "dantleech", + "email": "dan.t.leech@gmail.com" + } + ], + "repositories": [ + { + "type": "path", + "url": "./*" + } + ], + "require": { + "dantleech/symlinked": "1.0.0" + } +} diff --git a/tests/Integration/Composer/project/symlinked-package/Class.php b/tests/Integration/Composer/project/symlinked-package/Class.php new file mode 100644 index 00000000..20a783cc --- /dev/null +++ b/tests/Integration/Composer/project/symlinked-package/Class.php @@ -0,0 +1,7 @@ +