Chris@0: ['tests', 'driver-testsuite'], Chris@0: 'behat/mink-browserkit-driver' => ['tests'], Chris@0: 'behat/mink-goutte-driver' => ['tests'], Chris@18: 'brumann/polyfill-unserialize' => ['tests'], Chris@0: 'drupal/coder' => ['coder_sniffer/Drupal/Test', 'coder_sniffer/DrupalPractice/Test'], Chris@0: 'doctrine/cache' => ['tests'], Chris@0: 'doctrine/collections' => ['tests'], Chris@0: 'doctrine/common' => ['tests'], Chris@0: 'doctrine/inflector' => ['tests'], Chris@0: 'doctrine/instantiator' => ['tests'], Chris@0: 'egulias/email-validator' => ['documentation', 'tests'], Chris@0: 'fabpot/goutte' => ['Goutte/Tests'], Chris@0: 'guzzlehttp/promises' => ['tests'], Chris@0: 'guzzlehttp/psr7' => ['tests'], Chris@0: 'jcalderonzumba/gastonjs' => ['docs', 'examples', 'tests'], Chris@0: 'jcalderonzumba/mink-phantomjs-driver' => ['tests'], Chris@0: 'masterminds/html5' => ['test'], Chris@0: 'mikey179/vfsStream' => ['src/test'], Chris@0: 'paragonie/random_compat' => ['tests'], Chris@18: 'pear/archive_tar' => ['tests'], Chris@18: 'pear/console_getopt' => ['tests'], Chris@18: 'pear/pear-core-minimal' => ['tests'], Chris@18: 'pear/pear_exception' => ['tests'], Chris@0: 'phpdocumentor/reflection-docblock' => ['tests'], Chris@0: 'phpunit/php-code-coverage' => ['tests'], Chris@0: 'phpunit/php-timer' => ['tests'], Chris@0: 'phpunit/php-token-stream' => ['tests'], Chris@0: 'phpunit/phpunit' => ['tests'], Chris@0: 'phpunit/php-mock-objects' => ['tests'], Chris@0: 'sebastian/comparator' => ['tests'], Chris@0: 'sebastian/diff' => ['tests'], Chris@0: 'sebastian/environment' => ['tests'], Chris@0: 'sebastian/exporter' => ['tests'], Chris@0: 'sebastian/global-state' => ['tests'], Chris@0: 'sebastian/recursion-context' => ['tests'], Chris@0: 'stack/builder' => ['tests'], Chris@0: 'symfony/browser-kit' => ['Tests'], Chris@0: 'symfony/class-loader' => ['Tests'], Chris@0: 'symfony/console' => ['Tests'], Chris@0: 'symfony/css-selector' => ['Tests'], Chris@0: 'symfony/debug' => ['Tests'], Chris@0: 'symfony/dependency-injection' => ['Tests'], Chris@0: 'symfony/dom-crawler' => ['Tests'], Chris@0: // @see \Drupal\Tests\Component\EventDispatcher\ContainerAwareEventDispatcherTest Chris@0: // 'symfony/event-dispatcher' => ['Tests'], Chris@0: 'symfony/http-foundation' => ['Tests'], Chris@0: 'symfony/http-kernel' => ['Tests'], Chris@0: 'symfony/process' => ['Tests'], Chris@0: 'symfony/psr-http-message-bridge' => ['Tests'], Chris@0: 'symfony/routing' => ['Tests'], Chris@0: 'symfony/serializer' => ['Tests'], Chris@0: 'symfony/translation' => ['Tests'], Chris@0: 'symfony/validator' => ['Tests', 'Resources'], Chris@0: 'symfony/yaml' => ['Tests'], Chris@0: 'symfony-cmf/routing' => ['Test', 'Tests'], Chris@0: 'twig/twig' => ['doc', 'ext', 'test'], Chris@0: ]; Chris@0: Chris@0: /** Chris@0: * Add vendor classes to Composer's static classmap. Chris@0: */ Chris@0: public static function preAutoloadDump(Event $event) { Chris@0: // Get the configured vendor directory. Chris@0: $vendor_dir = $event->getComposer()->getConfig()->get('vendor-dir'); Chris@0: Chris@0: // We need the root package so we can add our classmaps to its loader. Chris@0: $package = $event->getComposer()->getPackage(); Chris@0: // We need the local repository so that we can query and see if it's likely Chris@0: // that our files are present there. Chris@0: $repository = $event->getComposer()->getRepositoryManager()->getLocalRepository(); Chris@0: // This is, essentially, a null constraint. We only care whether the package Chris@0: // is present in the vendor directory yet, but findPackage() requires it. Chris@0: $constraint = new Constraint('>', ''); Chris@0: // It's possible that there is no classmap specified in a custom project Chris@0: // composer.json file. We need one so we can optimize lookup for some of our Chris@0: // dependencies. Chris@0: $autoload = $package->getAutoload(); Chris@0: if (!isset($autoload['classmap'])) { Chris@0: $autoload['classmap'] = []; Chris@0: } Chris@0: // Check for our packages, and then optimize them if they're present. Chris@0: if ($repository->findPackage('symfony/http-foundation', $constraint)) { Chris@0: $autoload['classmap'] = array_merge($autoload['classmap'], [ Chris@0: $vendor_dir . '/symfony/http-foundation/Request.php', Chris@0: $vendor_dir . '/symfony/http-foundation/ParameterBag.php', Chris@0: $vendor_dir . '/symfony/http-foundation/FileBag.php', Chris@0: $vendor_dir . '/symfony/http-foundation/ServerBag.php', Chris@0: $vendor_dir . '/symfony/http-foundation/HeaderBag.php', Chris@0: ]); Chris@0: } Chris@0: if ($repository->findPackage('symfony/http-kernel', $constraint)) { Chris@0: $autoload['classmap'] = array_merge($autoload['classmap'], [ Chris@0: $vendor_dir . '/symfony/http-kernel/HttpKernel.php', Chris@0: $vendor_dir . '/symfony/http-kernel/HttpKernelInterface.php', Chris@0: $vendor_dir . '/symfony/http-kernel/TerminableInterface.php', Chris@0: ]); Chris@0: } Chris@0: $package->setAutoload($autoload); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Ensures that .htaccess and web.config files are present in Composer root. Chris@0: * Chris@0: * @param \Composer\Script\Event $event Chris@0: */ Chris@0: public static function ensureHtaccess(Event $event) { Chris@0: Chris@0: // The current working directory for composer scripts is where you run Chris@0: // composer from. Chris@0: $vendor_dir = $event->getComposer()->getConfig()->get('vendor-dir'); Chris@0: Chris@0: // Prevent access to vendor directory on Apache servers. Chris@0: $htaccess_file = $vendor_dir . '/.htaccess'; Chris@0: if (!file_exists($htaccess_file)) { Chris@0: file_put_contents($htaccess_file, FileStorage::htaccessLines(TRUE) . "\n"); Chris@0: } Chris@0: Chris@0: // Prevent access to vendor directory on IIS servers. Chris@0: $webconfig_file = $vendor_dir . '/web.config'; Chris@0: if (!file_exists($webconfig_file)) { Chris@0: $lines = << Chris@0: Chris@0: Chris@0: Chris@0: Chris@0: Chris@0: Chris@0: EOT; Chris@0: file_put_contents($webconfig_file, $lines . "\n"); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@14: * Fires the drupal-phpunit-upgrade script event if necessary. Chris@14: * Chris@14: * @param \Composer\Script\Event $event Chris@14: */ Chris@14: public static function upgradePHPUnit(Event $event) { Chris@14: $repository = $event->getComposer()->getRepositoryManager()->getLocalRepository(); Chris@14: // This is, essentially, a null constraint. We only care whether the package Chris@14: // is present in the vendor directory yet, but findPackage() requires it. Chris@14: $constraint = new Constraint('>', ''); Chris@14: $phpunit_package = $repository->findPackage('phpunit/phpunit', $constraint); Chris@14: if (!$phpunit_package) { Chris@14: // There is nothing to do. The user is probably installing using the Chris@14: // --no-dev flag. Chris@14: return; Chris@14: } Chris@14: Chris@17: // If the PHP version is 7.0 or above and PHPUnit is less than version 6 Chris@14: // call the drupal-phpunit-upgrade script to upgrade PHPUnit. Chris@14: if (!static::upgradePHPUnitCheck($phpunit_package->getVersion())) { Chris@14: $event->getComposer() Chris@14: ->getEventDispatcher() Chris@14: ->dispatchScript('drupal-phpunit-upgrade'); Chris@14: } Chris@14: } Chris@14: Chris@14: /** Chris@14: * Determines if PHPUnit needs to be upgraded. Chris@14: * Chris@14: * This method is located in this file because it is possible that it is Chris@14: * called before the autoloader is available. Chris@14: * Chris@14: * @param string $phpunit_version Chris@14: * The PHPUnit version string. Chris@14: * Chris@14: * @return bool Chris@14: * TRUE if the PHPUnit needs to be upgraded, FALSE if not. Chris@14: */ Chris@14: public static function upgradePHPUnitCheck($phpunit_version) { Chris@17: return !(version_compare(PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION, '7.0') >= 0 && version_compare($phpunit_version, '6.1') < 0); Chris@14: } Chris@14: Chris@14: /** Chris@0: * Remove possibly problematic test files from vendored projects. Chris@0: * Chris@0: * @param \Composer\Installer\PackageEvent $event Chris@0: * A PackageEvent object to get the configured composer vendor directories Chris@0: * from. Chris@0: */ Chris@0: public static function vendorTestCodeCleanup(PackageEvent $event) { Chris@0: $vendor_dir = $event->getComposer()->getConfig()->get('vendor-dir'); Chris@0: $io = $event->getIO(); Chris@0: $op = $event->getOperation(); Chris@0: if ($op->getJobType() == 'update') { Chris@0: $package = $op->getTargetPackage(); Chris@0: } Chris@0: else { Chris@0: $package = $op->getPackage(); Chris@0: } Chris@0: $package_key = static::findPackageKey($package->getName()); Chris@0: $message = sprintf(" Processing %s", $package->getPrettyName()); Chris@0: if ($io->isVeryVerbose()) { Chris@0: $io->write($message); Chris@0: } Chris@0: if ($package_key) { Chris@0: foreach (static::$packageToCleanup[$package_key] as $path) { Chris@0: $dir_to_remove = $vendor_dir . '/' . $package_key . '/' . $path; Chris@0: $print_message = $io->isVeryVerbose(); Chris@0: if (is_dir($dir_to_remove)) { Chris@0: if (static::deleteRecursive($dir_to_remove)) { Chris@0: $message = sprintf(" Removing directory '%s'", $path); Chris@0: } Chris@0: else { Chris@0: // Always display a message if this fails as it means something has Chris@0: // gone wrong. Therefore the message has to include the package name Chris@0: // as the first informational message might not exist. Chris@0: $print_message = TRUE; Chris@0: $message = sprintf(" Failure removing directory '%s' in package %s.", $path, $package->getPrettyName()); Chris@0: } Chris@0: } Chris@0: else { Chris@0: // If the package has changed or the --prefer-dist version does not Chris@0: // include the directory this is not an error. Chris@0: $message = sprintf(" Directory '%s' does not exist", $path); Chris@0: } Chris@0: if ($print_message) { Chris@0: $io->write($message); Chris@0: } Chris@0: } Chris@0: Chris@0: if ($io->isVeryVerbose()) { Chris@0: // Add a new line to separate this output from the next package. Chris@0: $io->write(""); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Find the array key for a given package name with a case-insensitive search. Chris@0: * Chris@0: * @param string $package_name Chris@0: * The package name from composer. This is always already lower case. Chris@0: * Chris@0: * @return string|null Chris@0: * The string key, or NULL if none was found. Chris@0: */ Chris@0: protected static function findPackageKey($package_name) { Chris@0: $package_key = NULL; Chris@0: // In most cases the package name is already used as the array key. Chris@0: if (isset(static::$packageToCleanup[$package_name])) { Chris@0: $package_key = $package_name; Chris@0: } Chris@0: else { Chris@0: // Handle any mismatch in case between the package name and array key. Chris@0: // For example, the array key 'mikey179/vfsStream' needs to be found Chris@0: // when composer returns a package name of 'mikey179/vfsstream'. Chris@0: foreach (static::$packageToCleanup as $key => $dirs) { Chris@0: if (strtolower($key) === $package_name) { Chris@0: $package_key = $key; Chris@0: break; Chris@0: } Chris@0: } Chris@0: } Chris@0: return $package_key; Chris@0: } Chris@0: Chris@0: /** Chris@17: * Removes Composer's timeout so that scripts can run indefinitely. Chris@17: */ Chris@17: public static function removeTimeout() { Chris@17: ProcessExecutor::setTimeout(0); Chris@17: } Chris@17: Chris@17: /** Chris@0: * Helper method to remove directories and the files they contain. Chris@0: * Chris@0: * @param string $path Chris@0: * The directory or file to remove. It must exist. Chris@0: * Chris@0: * @return bool Chris@0: * TRUE on success or FALSE on failure. Chris@0: */ Chris@0: protected static function deleteRecursive($path) { Chris@0: if (is_file($path) || is_link($path)) { Chris@0: return unlink($path); Chris@0: } Chris@0: $success = TRUE; Chris@0: $dir = dir($path); Chris@0: while (($entry = $dir->read()) !== FALSE) { Chris@0: if ($entry == '.' || $entry == '..') { Chris@0: continue; Chris@0: } Chris@0: $entry_path = $path . '/' . $entry; Chris@0: $success = static::deleteRecursive($entry_path) && $success; Chris@0: } Chris@0: $dir->close(); Chris@0: Chris@0: return rmdir($path) && $success; Chris@0: } Chris@0: Chris@0: }