From 86128332829d6fc36e506e10589ee12e97b25fd3 Mon Sep 17 00:00:00 2001 From: Moshe Weitzman Date: Sat, 11 Nov 2023 16:16:24 -0500 Subject: [PATCH] Drastically simplify using Composer Runtime API --- .gitignore | 1 + composer.json | 34 +++- src/DrupalFinder.php | 267 +------------------------ tests/Drupal7FinderTest.php | 169 ---------------- tests/Drupal8FinderTest.php | 343 --------------------------------- tests/DrupalFinderTest.php | 15 ++ tests/DrupalFinderTestBase.php | 184 ------------------ 7 files changed, 49 insertions(+), 964 deletions(-) delete mode 100644 tests/Drupal7FinderTest.php delete mode 100644 tests/Drupal8FinderTest.php create mode 100644 tests/DrupalFinderTest.php delete mode 100644 tests/DrupalFinderTestBase.php diff --git a/.gitignore b/.gitignore index 8f7045c..3b5b6d9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /composer.lock /vendor/ /.phpunit.result.cache +/web diff --git a/composer.json b/composer.json index 703c2a8..4920316 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "webflo/drupal-finder", - "description": "Helper class to locate a Drupal installation from a given path.", + "description": "Helper class to locate a Drupal installation.", "license": "GPL-2.0-or-later", "type": "library", "authors": [ @@ -10,20 +10,34 @@ } ], "require": { - "ext-json": "*" - }, - "autoload": { - "classmap": [ - "src/DrupalFinder.php" - ] + "composer-runtime-api": "^2.2" }, "autoload-dev": { "psr-4": { - "DrupalFinder\\Tests\\": "tests/" + "DrupalFinder\\Tests\\": "tests/", + "DrupalFinder\\": "src/" } }, "require-dev": { - "phpunit/phpunit": "^8.5.14", - "mikey179/vfsstream": "^1.6" + "composer/installers": "^2", + "drupal/core-recommended": "^10", + "phpunit/phpunit": "^9" + }, + "config": { + "allow-plugins": { + "composer/installers": true + }, + "optimize-autoloader": true, + "preferred-install": "dist", + "sort-packages": true, + "process-timeout": 9600, + "platform": { + "php": "8.1" + } + }, + "extra": { + "installer-paths": { + "web/core": ["type:drupal-core"] + } } } diff --git a/src/DrupalFinder.php b/src/DrupalFinder.php index ffbcecd..4ad8065 100644 --- a/src/DrupalFinder.php +++ b/src/DrupalFinder.php @@ -7,92 +7,10 @@ namespace DrupalFinder; +use Composer\InstalledVersions; + class DrupalFinder { - /** - * Drupal root environment variable. - */ - const ENV_DRUPAL_ROOT = 'DRUPAL_FINDER_DRUPAL_ROOT'; - - /** - * Composer root environment variable. - */ - const ENV_COMPOSER_ROOT = 'DRUPAL_FINDER_COMPOSER_ROOT'; - - /** - * Vendor directory environment variable. - */ - const ENV_VENDOR_DIR = 'DRUPAL_FINDER_VENDOR_DIR'; - - /** - * Drupal web public directory. - * - * @var string - */ - private $drupalRoot; - - /** - * Drupal package composer directory. - * - * @var bool - */ - private $composerRoot; - - /** - * Composer vendor directory. - * - * @var string - * - * @see https://getcomposer.org/doc/06-config.md#vendor-dir - */ - private $vendorDir; - - /** - * Initialize finder. - * - * Optionally pass the starting path. - * - * @param string|null $start_path - * The path to begin the search from. - * - * @throws \Exception - * @todo Make $start_path mandatory in v2. - */ - public function __construct($start_path = null) { - // Initialize path variables to false, indicating their locations are - // not yet known. - $this->drupalRoot = false; - $this->composerRoot = false; - $this->vendorDir = false; - - // If a starting path was provided, attempt to locate and set path - // variables. - if (!empty($start_path)) { - $this->discoverRoots($start_path); - } - } - - /** - * Locate Drupal, Composer, and vendor directory paths. - * - * @param string $start_path - * The path to begin the search from. - * - * @return bool - * True if the Drupal root was identified, false otherwise. - * - * @throws \Exception - * - * @deprecated Will be removed in v2. Future usage should instantiate - * a new DrupalFinder object by passing the starting path to its - * constructor. - */ - public function locateRoot($start_path) - { - $this->discoverRoots($start_path); - return !empty($this->getDrupalRoot()); - } - /** * Get the Drupal root. * @@ -101,9 +19,8 @@ public function locateRoot($start_path) */ public function getDrupalRoot() { - $environment_path = $this->getValidEnvironmentVariablePath(self::ENV_DRUPAL_ROOT); - - return !empty($environment_path) ? $environment_path : $this->drupalRoot; + $core = InstalledVersions::getInstallPath('drupal/core'); + return $core ? realpath(dirname($core)) : false; } /** @@ -114,8 +31,7 @@ public function getDrupalRoot() */ public function getComposerRoot() { - $environment_path = $this->getValidEnvironmentVariablePath(self::ENV_COMPOSER_ROOT); - return !empty($environment_path) ? $environment_path : $this->composerRoot; + return realpath(dirname($this->getVendorDir())); } /** @@ -126,175 +42,10 @@ public function getComposerRoot() */ public function getVendorDir() { - $environment_path = $this->getValidEnvironmentVariablePath(self::ENV_VENDOR_DIR); - return !empty($environment_path) ? $environment_path : $this->vendorDir; - } - - /** - * Discover all valid paths. - * - * @param $start_path - * The path to start the search from. - * - * @throws \Exception - */ - protected function discoverRoots($start_path) { - // Since we are discovering, reset all path variables. - $this->drupalRoot = false; - $this->composerRoot = false; - $this->vendorDir = false; - - foreach (array(true, false) as $follow_symlinks) { - $path = $start_path; - if ($follow_symlinks && is_link($path)) { - $path = realpath($path); - } - - // Check the start path. - if ($this->findAndValidateRoots($path)) { - return; - } else { - // Move up dir by dir and check each. - while ($path = $this->shiftPathUp($path)) { - if ($follow_symlinks && is_link($path)) { - $path = realpath($path); - } - if ($this->findAndValidateRoots($path)) { - return; - } - } - } - } - } - - /** - * Determine if a valid Drupal root exists. - * - * In addition, set any valid path properties if they are found. - * - * @param $path - * The starting path to search from. - * - * @return bool - * True if all roots were discovered and validated. False otherwise. - */ - protected function findAndValidateRoots($path) - { - - if (!empty($path) && is_dir($path) && file_exists($path . '/autoload.php') && file_exists($path . '/' . $this->getComposerFileName())) { - // Additional check for the presence of core/composer.json to - // grant it is not a Drupal 7 site with a base folder named "core". - $candidate = 'core/includes/common.inc'; - if (file_exists($path . '/' . $candidate) && file_exists($path . '/core/core.services.yml')) { - if (file_exists($path . '/core/misc/drupal.js') || file_exists($path . '/core/assets/js/drupal.js')) { - $this->composerRoot = $path; - $this->drupalRoot = $path; - $this->vendorDir = $this->composerRoot . '/vendor'; - } - } - } - if (!empty($path) && is_dir($path) && file_exists($path . '/' . $this->getComposerFileName())) { - $json = json_decode( - file_get_contents($path . '/' . $this->getComposerFileName()), - true - ); - - if (is_null($json)) { - throw new \Exception('Unable to decode ' . $path . '/' . $this->getComposerFileName()); - } - - if (is_array($json)) { - if (isset($json['extra']['installer-paths']) && is_array($json['extra']['installer-paths'])) { - foreach ($json['extra']['installer-paths'] as $install_path => $items) { - if (in_array('type:drupal-core', $items) || - in_array('drupal/core', $items) || - in_array('drupal/drupal', $items)) { - $this->composerRoot = $path; - // @todo: Remove this magic and detect the major version instead. - if (($install_path == 'core') || ((isset($json['name'])) && ($json['name'] == 'drupal/drupal'))) { - $install_path = ''; - } elseif (substr($install_path, -5) == '/core') { - $install_path = substr($install_path, 0, -5); - } - $this->drupalRoot = rtrim($path . '/' . $install_path, '/'); - $this->vendorDir = $this->composerRoot . '/vendor'; - } - } - } - } - } - if ($this->composerRoot && file_exists($this->composerRoot . '/' . $this->getComposerFileName())) { - $json = json_decode( - file_get_contents($path . '/' . $this->getComposerFileName()), - true - ); - if (is_array($json) && isset($json['config']['vendor-dir'])) { - $this->vendorDir = $this->composerRoot . '/' . $json['config']['vendor-dir']; - } - } - - return $this->allPathsDiscovered(); - } - - /** - * @return string - */ - protected function getComposerFileName() - { - return trim(getenv('COMPOSER')) ?: 'composer.json'; - } - - /** - * Helper function to quickly determine whether or not all paths were discovered. - * - * @return bool - * True if all paths have been discovered, false if one or more haven't been found. - */ - protected function allPathsDiscovered() { - return !empty($this->drupalRoot) && !empty($this->composerRoot) && !empty($this->vendorDir); - } - - /** - * Helper function to quickly determine whether or not all paths are known. - * - * @return bool - * True if all paths are known, false if one or more paths are unknown. - */ - protected function allPathsKnown() { - return !empty($this->getDrupalRoot()) && !empty($this->getComposerRoot()) && !empty($this->getVendorDir()); - } - - /** - * Get path stored in environment variable. - * - * @param string $variable - * The name of the environment variable to retrieve the path from. - * - * @return false|string - * A path if it is valid. False otherwise. - */ - protected function getValidEnvironmentVariablePath($variable) { - $path = getenv($variable); - if (is_string($path) && is_dir($path)) { - return $path; - } - return false; - } - - /** - * Returns parent directory. - * - * @param string - * Path to start from - * - * @return string|false - * Parent path of given path or false when $path is filesystem root - */ - private function shiftPathUp($path) - { - $parent = dirname($path); - - return in_array($parent, ['.', $path]) ? false : $parent; + // See https://getcomposer.org/doc/07-runtime.md#autoloader-path-in-binaries + // PHPUnit replaces $_composer_autoload_path with its constant in vendor/phpunit/phpunit/phpunit + $autoload_path = $GLOBALS['_composer_autoload_path'] ?? PHPUNIT_COMPOSER_INSTALL; + return isset($autoload_path) ? realpath(dirname($autoload_path)) : false; } } diff --git a/tests/Drupal7FinderTest.php b/tests/Drupal7FinderTest.php deleted file mode 100644 index 9d84d61..0000000 --- a/tests/Drupal7FinderTest.php +++ /dev/null @@ -1,169 +0,0 @@ - [ - 'common.inc' => '', - ], - 'misc' => [ - 'drupal.js' => '', - ], - 'sites' => [ - 'all' => [ - 'modules' => [] - ] - ] - ]; - - /** - * @return array - */ - protected function getDrupalComposerStructure() - { - $fileStructure = [ - 'web' => static::$fileStructure, - 'composer.json' => [ - 'require' => [ - 'drupal/drupal' => '*', - ], - 'extra' => [ - 'installer-paths' => [ - 'web/' => [ - 'type:drupal-core', - ], - ], - ], - ], - 'vendor' => [], - ]; - return $fileStructure; - } - - public function testDrupalComposerStructure() - { - $fileStructure = $this->getDrupalComposerStructure(); - $this->assertComposerStructure($fileStructure); - } - - public function testDrupalComposerStructureWithoutRequire() - { - $fileStructure = [ - 'web' => static::$fileStructure, - 'composer.json' => [ - 'extra' => [ - 'installer-paths' => [ - 'web' => [ - 'drupal/drupal', - ], - ], - ], - ], - ]; - $this->assertComposerStructure($fileStructure); - } - - public function testNoDrupalRootWithRealFilesystem() - { - $finder = new DrupalFinder(); - $root = $this->tempdir(sys_get_temp_dir()); - - $this->assertFalse($finder->locateRoot($root)); - $this->assertFalse($finder->getDrupalRoot()); - $this->assertFalse($finder->getComposerRoot()); - $this->assertFalse($finder->getVendorDir()); - } - - public function testDrupalComposerStructureWithRealFilesystem() - { - $finder = new DrupalFinder(); - $root = $this->tempdir(sys_get_temp_dir()); - $this->dumpToFileSystem($this->getDrupalComposerStructure(), $root); - - $this->assertTrue($finder->locateRoot($root)); - $this->assertSame($root . '/web', $finder->getDrupalRoot()); - $this->assertSame($root, $finder->getComposerRoot()); - $this->assertSame($root . '/vendor', $finder->getVendorDir()); - - // Test symlink implementation - $symlink = $this->tempdir(sys_get_temp_dir()); - $this->symlink($root, $symlink . '/foo'); - - $this->assertTrue($finder->locateRoot($symlink . '/foo')); - $this->assertSame($root . '/web', $finder->getDrupalRoot()); - $this->assertSame($root, $finder->getComposerRoot()); - $this->assertSame($root . '/vendor', $finder->getVendorDir()); - } - - public function testDrupalWithLinkedModule() - { - $finder = new DrupalFinder(); - $root = $this->tempdir(sys_get_temp_dir()); - $this->dumpToFileSystem($this->getDrupalComposerStructure(), $root); - - $module = $this->tempdir(sys_get_temp_dir()); - $module_link = $root . '/web/sites/all/modules/foo'; - $this->symlink($module, $module_link); - - $this->assertTrue($finder->locateRoot($module_link)); - $this->assertSame($root . '/web', realpath($finder->getDrupalRoot())); - $this->assertSame($root, realpath($finder->getComposerRoot())); - $this->assertSame($root . '/vendor', realpath($finder->getVendorDir())); - } - - public function testDrupalWithCustomVendor() - { - $finder = new DrupalFinder(); - $root = $this->tempdir(sys_get_temp_dir()); - $fileStructure = $this->getDrupalComposerStructure(); - $composerJson = $fileStructure['composer.json']; - $composerJson['config']['vendor-dir'] = 'vendor-foo'; - $fileStructure['composer.json'] = $composerJson; - $fileStructure['vendor-foo'] = []; - $this->dumpToFileSystem($fileStructure, $root); - - $this->assertTrue($finder->locateRoot($root)); - $this->assertSame($root . '/web', realpath($finder->getDrupalRoot())); - $this->assertSame($root, realpath($finder->getComposerRoot())); - $this->assertSame($root . '/vendor-foo', realpath($finder->getVendorDir())); - } - - /** - * @param $fileStructure - */ - protected function assertComposerStructure($fileStructure) - { - $finder = new DrupalFinder(); - $fileStructure = $this->prepareFileStructure($fileStructure); - $root = vfsStream::setup('root', null, $fileStructure); - $this->assertTrue($finder->locateRoot($root->url() . '/web')); - $this->assertSame('vfs://root/web', $finder->getDrupalRoot()); - $this->assertSame('vfs://root', $finder->getComposerRoot()); - $this->assertSame('vfs://root/vendor', $finder->getVendorDir()); - - $this->assertTrue($finder->locateRoot($root->url() . '/web/misc')); - $this->assertSame('vfs://root/web', $finder->getDrupalRoot()); - $this->assertSame('vfs://root', $finder->getComposerRoot()); - $this->assertSame('vfs://root/vendor', $finder->getVendorDir()); - - $this->assertTrue($finder->locateRoot($root->url())); - $this->assertSame('vfs://root/web', $finder->getDrupalRoot()); - $this->assertSame('vfs://root', $finder->getComposerRoot()); - $this->assertSame('vfs://root/vendor', $finder->getVendorDir()); - - $root = vfsStream::setup( - 'root', - null, - ['nested_folder' => $fileStructure] - ); - $this->assertFalse($finder->locateRoot($root->url())); - $this->assertFalse($finder->getDrupalRoot()); - $this->assertFalse($finder->getComposerRoot()); - $this->assertFalse($finder->getVendorDir()); - } -} diff --git a/tests/Drupal8FinderTest.php b/tests/Drupal8FinderTest.php deleted file mode 100644 index 2d00e44..0000000 --- a/tests/Drupal8FinderTest.php +++ /dev/null @@ -1,343 +0,0 @@ - '', - 'composer.json' => [ - 'extra' => [ - 'installer-paths' => [ - 'core' => [ - 'type:drupal-core' - ] - ] - ] - ], - 'core' => [ - 'includes' => [ - 'common.inc' => '', - ], - 'misc' => [ - 'drupal.js' => '', - ], - 'core.services.yml' => '', - ], - 'modules' => [], - 'vendor' => [], - ]; - - protected static $fileStructureDrupal_8_8_x = [ - 'autoload.php' => '', - 'composer.json' => [ - 'name' => 'drupal/drupal', - 'require' => [ - 'drupal/core' => 'self.version', - ], - 'extra' => [ - 'installer-paths' => [ - 'vendor/drupal/core' => [ - 'type:drupal-core', - ], - ], - ], - ], - 'core' => [ - 'includes' => [ - 'common.inc' => '', - ], - 'misc' => [ - 'drupal.js' => '', - ], - 'core.services.yml' => '', - ], - 'modules' => [], - 'vendor' => [], - ]; - - /** - * @return array - */ - protected function getDrupalComposerStructure() - { - $fileStructure = [ - 'web' => static::$fileStructure, - 'composer.json' => [ - 'require' => [ - 'drupal/core' => '*', - ], - 'extra' => [ - 'installer-paths' => [ - 'web/core' => [ - 'type:drupal-core', - ], - ], - ], - ], - 'vendor' => [], - ]; - unset($fileStructure['web']['composer.json']); - unset($fileStructure['web']['vendor']); - - return $fileStructure; - } - - public function testDrupalDefaultStructure() - { - $finder = new DrupalFinder(); - $root = vfsStream::setup('root', null, $this->prepareFileStructure(static::$fileStructure)); - - $this->assertTrue($finder->locateRoot($root->url())); - $this->assertSame('vfs://root', $finder->getDrupalRoot()); - $this->assertSame('vfs://root', $finder->getComposerRoot()); - $this->assertSame('vfs://root/vendor', $finder->getVendorDir()); - - $this->assertTrue($finder->locateRoot($root->url() . '/misc')); - $this->assertSame('vfs://root', $finder->getDrupalRoot()); - $this->assertSame('vfs://root', $finder->getComposerRoot()); - $this->assertSame('vfs://root/vendor', $finder->getVendorDir()); - - $root = vfsStream::setup( - 'root', - null, - ['project' => $this->prepareFileStructure(static::$fileStructure)] - ); - $this->assertFalse( - $finder->locateRoot($root->url()), - 'Not in the scope of the project' - ); - $this->assertFalse($finder->getDrupalRoot()); - $this->assertFalse($finder->getComposerRoot()); - $this->assertFalse($finder->getVendorDir()); - } - - public function testDrupalDefaultStructure_8_8_x() - { - $finder = new DrupalFinder(); - $root = vfsStream::setup('root', null, $this->prepareFileStructure(static::$fileStructureDrupal_8_8_x)); - - $this->assertTrue($finder->locateRoot($root->url())); - $this->assertSame('vfs://root', $finder->getDrupalRoot()); - $this->assertSame('vfs://root', $finder->getComposerRoot()); - $this->assertSame('vfs://root/vendor', $finder->getVendorDir()); - - $this->assertTrue($finder->locateRoot($root->url() . '/misc')); - $this->assertSame('vfs://root', $finder->getDrupalRoot()); - $this->assertSame('vfs://root', $finder->getComposerRoot()); - $this->assertSame('vfs://root/vendor', $finder->getVendorDir()); - - $root = vfsStream::setup( - 'root', - null, - ['project' => $this->prepareFileStructure(static::$fileStructure)] - ); - $this->assertFalse( - $finder->locateRoot($root->url()), - 'Not in the scope of the project' - ); - $this->assertFalse($finder->getDrupalRoot()); - $this->assertFalse($finder->getComposerRoot()); - $this->assertFalse($finder->getVendorDir()); - } - - public function testDrupalComposerStructure() - { - $fileStructure = $this->getDrupalComposerStructure(); - $this->assertComposerStructure($fileStructure); - } - - public function testDrupalComposerStructureWithCustomRoot() - { - $finder = new DrupalFinder(); - $fileStructure = [ - 'src' => static::$fileStructure, - 'composer.json' => [ - 'require' => [ - 'drupal/core' => '*', - ], - 'extra' => [ - 'installer-paths' => [ - 'src/core' => [ - 'type:drupal-core', - ], - ], - ], - ], - 'vendor' => [], - ]; - unset($fileStructure['src']['composer.json']); - unset($fileStructure['src']['vendor']); - - $fileStructure = $this->prepareFileStructure($fileStructure); - $root = vfsStream::setup('root', null, $fileStructure); - $this->assertTrue($finder->locateRoot($root->url() . '/src')); - $this->assertSame('vfs://root/src', $finder->getDrupalRoot()); - $this->assertSame('vfs://root', $finder->getComposerRoot()); - $this->assertSame('vfs://root/vendor', $finder->getVendorDir()); - - $this->assertTrue($finder->locateRoot($root->url() . '/src/misc')); - $this->assertSame('vfs://root/src', $finder->getDrupalRoot()); - $this->assertSame('vfs://root', $finder->getComposerRoot()); - $this->assertSame('vfs://root/vendor', $finder->getVendorDir()); - - $this->assertTrue($finder->locateRoot($root->url())); - $this->assertSame('vfs://root/src', $finder->getDrupalRoot()); - $this->assertSame('vfs://root', $finder->getComposerRoot()); - $this->assertSame('vfs://root/vendor', $finder->getVendorDir()); - - $root = vfsStream::setup( - 'root', - null, - ['nested_folder' => $fileStructure] - ); - $this->assertFalse($finder->locateRoot($root->url())); - $this->assertFalse($finder->getDrupalRoot()); - $this->assertFalse($finder->getComposerRoot()); - $this->assertFalse($finder->getVendorDir()); - } - - public function testDrupalComposerStructureWithoutRequire() - { - $fileStructure = [ - 'web' => static::$fileStructure, - 'composer.json' => [ - 'extra' => [ - 'installer-paths' => [ - 'web/core' => [ - 'drupal/core', - ], - ], - ], - ], - ]; - unset($fileStructure['web']['composer.json']); - $this->assertComposerStructure($fileStructure); - } - - public function testNoDrupalRootWithRealFilesystem() - { - $finder = new DrupalFinder(); - $root = $this->tempdir(sys_get_temp_dir()); - - $this->assertFalse($finder->locateRoot($root)); - $this->assertFalse($finder->getDrupalRoot()); - $this->assertFalse($finder->getComposerRoot()); - $this->assertFalse($finder->getVendorDir()); - } - - public function testDrupalDefaultStructureWithRealFilesystem() - { - $finder = new DrupalFinder(); - $root = $this->tempdir(sys_get_temp_dir()); - $this->dumpToFileSystem(static::$fileStructure, $root); - - $this->assertTrue($finder->locateRoot($root)); - $this->assertSame($root, $finder->getDrupalRoot()); - $this->assertSame($root, $finder->getComposerRoot()); - $this->assertSame($root . '/vendor', $finder->getVendorDir()); - - // Test symlink implementation - $symlink = $this->tempdir(sys_get_temp_dir()); - $this->symlink($root, $symlink . '/foo'); - - $this->assertTrue($finder->locateRoot($symlink . '/foo')); - $this->assertSame($root, $finder->getDrupalRoot()); - $this->assertSame($root, $finder->getComposerRoot()); - $this->assertSame($root . '/vendor', $finder->getVendorDir()); - } - - public function testDrupalComposerStructureWithRealFilesystem() - { - $finder = new DrupalFinder(); - $root = $this->tempdir(sys_get_temp_dir()); - $this->dumpToFileSystem($this->getDrupalComposerStructure(), $root); - - $this->assertTrue($finder->locateRoot($root)); - $this->assertSame($root . '/web', $finder->getDrupalRoot()); - $this->assertSame($root, $finder->getComposerRoot()); - $this->assertSame($root . '/vendor', $finder->getVendorDir()); - - // Test symlink implementation - $symlink = $this->tempdir(sys_get_temp_dir()); - $this->symlink($root, $symlink . '/foo'); - - $this->assertTrue($finder->locateRoot($symlink . '/foo')); - $this->assertSame($root . '/web', $finder->getDrupalRoot()); - $this->assertSame($root, $finder->getComposerRoot()); - $this->assertSame($root . '/vendor', $finder->getVendorDir()); - } - - public function testDrupalWithLinkedModule() - { - $finder = new DrupalFinder(); - $root = $this->tempdir(sys_get_temp_dir()); - $this->dumpToFileSystem(static::$fileStructure, $root); - - $module = $this->tempdir(sys_get_temp_dir()); - $module_link = $root . '/modules/foo'; - $this->symlink($module, $module_link); - - $this->assertTrue($finder->locateRoot($module_link)); - $this->assertSame($root, realpath($finder->getDrupalRoot())); - $this->assertSame($root, realpath($finder->getComposerRoot())); - $this->assertSame($root . '/vendor', realpath($finder->getVendorDir())); - } - - public function testDrupalWithCustomVendor() - { - $finder = new DrupalFinder(); - $root = $this->tempdir(sys_get_temp_dir()); - $fileStructure = static::$fileStructure; - $fileStructure['composer.json'] = [ - 'config' => [ - 'vendor-dir' => 'vendor-foo' - ] - ]; - $fileStructure['vendor-foo'] = []; - $this->dumpToFileSystem($fileStructure, $root); - - $this->assertTrue($finder->locateRoot($root)); - $this->assertSame($root, realpath($finder->getDrupalRoot())); - $this->assertSame($root, realpath($finder->getComposerRoot())); - $this->assertSame($root . '/vendor-foo', realpath($finder->getVendorDir())); - } - - /** - * @param $fileStructure - */ - protected function assertComposerStructure($fileStructure) - { - $finder = new DrupalFinder(); - $fileStructure = $this->prepareFileStructure($fileStructure); - $root = vfsStream::setup('root', null, $fileStructure); - $this->assertTrue($finder->locateRoot($root->url() . '/web')); - $this->assertSame('vfs://root/web', $finder->getDrupalRoot()); - $this->assertSame('vfs://root', $finder->getComposerRoot()); - $this->assertSame('vfs://root/vendor', $finder->getVendorDir()); - - $this->assertTrue($finder->locateRoot($root->url() . '/web/misc')); - $this->assertSame('vfs://root/web', $finder->getDrupalRoot()); - $this->assertSame('vfs://root', $finder->getComposerRoot()); - $this->assertSame('vfs://root/vendor', $finder->getVendorDir()); - - $this->assertTrue($finder->locateRoot($root->url())); - $this->assertSame('vfs://root/web', $finder->getDrupalRoot()); - $this->assertSame('vfs://root', $finder->getComposerRoot()); - $this->assertSame('vfs://root/vendor', $finder->getVendorDir()); - - $root = vfsStream::setup( - 'root', - null, - ['nested_folder' => $fileStructure] - ); - $this->assertFalse($finder->locateRoot($root->url())); - $this->assertFalse($finder->getDrupalRoot()); - $this->assertFalse($finder->getComposerRoot()); - $this->assertFalse($finder->getVendorDir()); - } - -} diff --git a/tests/DrupalFinderTest.php b/tests/DrupalFinderTest.php new file mode 100644 index 0000000..9f0e574 --- /dev/null +++ b/tests/DrupalFinderTest.php @@ -0,0 +1,15 @@ +assertSame(dirname(__DIR__) . '/web', $finder->getDrupalRoot()); + $this->assertSame(dirname(__DIR__) . '/vendor', $finder->getVendorDir()); + $this->assertSame(dirname(__DIR__), $finder->getComposerRoot()); + } +} \ No newline at end of file diff --git a/tests/DrupalFinderTestBase.php b/tests/DrupalFinderTestBase.php deleted file mode 100644 index d8c99a3..0000000 --- a/tests/DrupalFinderTestBase.php +++ /dev/null @@ -1,184 +0,0 @@ -envNameDrupal = DrupalFinder::ENV_DRUPAL_ROOT; - $this->envNameComposer = DrupalFinder::ENV_COMPOSER_ROOT; - $this->envNameVendor = DrupalFinder::ENV_VENDOR_DIR; - } - - protected function tearDown(): void - { - parent::tearDown(); - // Unset variables to ensure their values don't carry over into other - // tests that are going to run. - putenv('DRUPAL_FINDER_DRUPAL_ROOT'); - putenv('DRUPAL_FINDER_COMPOSER_ROOT'); - putenv('DRUPAL_FINDER_VENDOR_DIR'); - } - - public function testOnlyDrupalEnvironmentVariable() { - $finder = new DrupalFinder(); - $fileStructure = [ - 'web' => [], - ]; - - $root = $this->tempdir(sys_get_temp_dir()); - $this->dumpToFileSystem($fileStructure, $root); - - $drupal_root = $root . '/web'; - - putenv("{$this->envNameDrupal}=$drupal_root"); - - // DrupalFinder::locateRoot should be true if the Drupal root is known. - $this->assertTrue($finder->locateRoot($root)); - $this->assertSame($finder->getDrupalRoot(), $drupal_root); - } - - public function testOnlyVendorEnvironmentVariable() { - $finder = new DrupalFinder(); - $fileStructure = [ - 'vendor' => [], - ]; - - $root = $this->tempdir(sys_get_temp_dir()); - $this->dumpToFileSystem($fileStructure, $root); - - $vendor_dir = $root . '/vendor'; - - putenv("{$this->envNameVendor}=$vendor_dir"); - - // DrupalFinder::locateRoot should be false since Drupal root is unknown. - $this->assertFalse($finder->locateRoot($root)); - $this->assertSame($finder->getVendorDir(), $vendor_dir); - } - - public function testOnlyComposerEnvironmentVariable() { - $finder = new DrupalFinder(); - $fileStructure = []; - - $root = $this->tempdir(sys_get_temp_dir()); - $this->dumpToFileSystem($fileStructure, $root); - - $composer_dir = $root; - - putenv("{$this->envNameComposer}=$composer_dir"); - - // DrupalFinder::locateRoot should be false since Drupal root is unknown. - $this->assertFalse($finder->locateRoot($root)); - $this->assertSame($finder->getComposerRoot(), $composer_dir); - } - - protected function dumpToFileSystem($fileStructure, $root) - { - $fileStructure = $this->prepareFileStructure($fileStructure); - foreach ($fileStructure as $name => $content) { - if (is_array($content)) { - mkdir($root . '/' . $name); - $this->dumpToFileSystem($content, $root . '/' . $name); - } else { - file_put_contents($root . '/' . $name, $content); - } - } - } - - protected function prepareFileStructure($fileStructure) - { - foreach ($fileStructure as $name => $content) { - if (($name === 'composer.json' || $name === 'composer.lock') && is_array($content)) { - $fileStructure[$name] = json_encode($content, JSON_UNESCAPED_SLASHES); - } elseif (is_array($content)) { - $fileStructure[$name] = $this->prepareFileStructure($content); - } - } - return $fileStructure; - } - - protected function tempdir($dir, $prefix = '', $mode = 0700) - { - if (substr($dir, -1) != '/') { - $dir .= '/'; - } - do { - $path = $dir . $prefix . mt_rand(0, 9999999); - } while (!mkdir($path, $mode)); - register_shutdown_function( - [static::class, 'tempdir_remove'], - $path - ); - - return realpath($path); - } - - public static function tempdir_remove($path) - { - if (is_link($path)) { - if (defined('PHP_WINDOWS_VERSION_BUILD')) { - rmdir($path); - } else { - unlink($path); - } - - return; - } - - foreach (scandir($path) as $child) { - if (in_array($child, ['.', '..'])) { - continue; - } - $child = "$path/$child"; - is_dir($child) ? static::tempdir_remove($child) : unlink($child); - } - rmdir($path); - } - - /** - * @param $target - * @param $link - * - * @throws SkippedTestError - */ - protected function symlink($target, $link) - { - try { - return symlink($target, $link); - } catch (Exception $e) { - if (defined('PHP_WINDOWS_VERSION_BUILD') - && strstr($e->getMessage(), WIN_ERROR_PRIVILEGE_NOT_HELD) - ) { - $this->markTestSkipped(<<<'MESSAGE' -No privilege to create symlinks. Run test as Administrator (elevated process). -MESSAGE - ); - } - throw $e; - } - } -} - -define('WIN_ERROR_PRIVILEGE_NOT_HELD', '1314');