From a97a0c7cfe06b97f6d1538518db7623da8f24fa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=C3=A9na=20Proxima?= <adam@phenaproxima.net> Date: Thu, 9 Mar 2023 08:36:17 -0500 Subject: [PATCH] Revert "Issue #3346628: ComposerPluginsValidatorTest fails with pcre.backtrack_limit=1000000 set" This reverts commit d227242887904ad13e0714c41b31500859ff3972. --- .cspell.json | 1 + .../src/Functional/UpdaterFormTestBase.php | 3 + drupalci.yml | 6 + .../src/FixtureManipulator.php | 109 +++++------------- pcre.ini | 8 ++ scripts/src/Converter.php | 1 + 6 files changed, 50 insertions(+), 78 deletions(-) create mode 100644 pcre.ini diff --git a/.cspell.json b/.cspell.json index 950ad4ab51..368b755a17 100644 --- a/.cspell.json +++ b/.cspell.json @@ -4,6 +4,7 @@ { "name": "automatic_updates", "path": "./dictionary.txt"} ], "ignorePaths": [ + "pcre.ini", "README.md" ] } diff --git a/automatic_updates_extensions/tests/src/Functional/UpdaterFormTestBase.php b/automatic_updates_extensions/tests/src/Functional/UpdaterFormTestBase.php index 061781f288..a154b52442 100644 --- a/automatic_updates_extensions/tests/src/Functional/UpdaterFormTestBase.php +++ b/automatic_updates_extensions/tests/src/Functional/UpdaterFormTestBase.php @@ -46,16 +46,19 @@ abstract class UpdaterFormTestBase extends UpdaterFormFunctionalTestBase { 'name' => 'drupal/semver_test', 'version' => '8.1.0', 'type' => 'drupal-module', + 'install_path' => '../../web/projects/semver_test', ]) ->addPackage([ 'name' => 'drupal/aaa_update_test', 'version' => '2.0.0', 'type' => 'drupal-module', + 'install_path' => '../../web/projects/aaa_update_test', ]) ->addPackage([ 'name' => 'drupal/automatic_updates_extensions_test_theme', 'version' => '2.0.0', 'type' => 'drupal-theme', + 'install_path' => '../../web/projects/automatic_updates_extensions_test_theme', ]) ->commitChanges(); $this->drupalPlaceBlock('local_tasks_block', ['primary' => TRUE]); diff --git a/drupalci.yml b/drupalci.yml index 2d5633337e..422d14d781 100644 --- a/drupalci.yml +++ b/drupalci.yml @@ -9,6 +9,12 @@ build: # Run code quality checks. container_command.commit-checks: commands: + # Disable the PCRE engine's JIT, since it causes Composer to die during the + # update process, but only on Drupal CI, and for reasons that are essentially + # impossible to trace into. The PCRE JIT is not necessary for Automatic Updates + # to work correctly, and disabling it is a known workaround. + # @see pcre.ini + - sudo cp modules/contrib/automatic_updates/pcre.ini /usr/local/etc/php/conf.d # @todo Replace in favor of commit-code-check.sh once https://www.drupal.org/project/drupal/issues/3314100 lands. - modules/contrib/automatic_updates/scripts/commit-code-check.sh --drupalci halt-on-fail: true diff --git a/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php b/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php index b08421244e..a333efff4d 100644 --- a/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php +++ b/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php @@ -11,14 +11,7 @@ use Symfony\Component\Filesystem\Filesystem as SymfonyFileSystem; use Drupal\Component\Serialization\Yaml; /** - * Manipulates a test fixture using Composer commands. - * - * The composer.json file CANNOT be safely created or modified using the - * json_encode() function, because Composer does not use a real JSON parser — it - * updates composer.json using \Composer\Json\JsonManipulator, which is known to - * choke in a number of scenarios. - * - * @see https://www.drupal.org/i/3346628 + * It manipulates. */ class FixtureManipulator { @@ -570,46 +563,6 @@ class FixtureManipulator { return $plain_output; } - /** - * Transform the received $package into options for `composer init`. - * - * @param array $package - * A Composer package definition. - * - * @return array - * The corresponding `composer init` options. - */ - private static function getComposerInitOptionsForPackage(array $package): array { - return array_filter(array_map(function ($k, $v) { - switch ($k) { - case 'name': - case 'description': - case 'type': - return "--$k=$v"; - - case 'require': - case 'require-dev': - $requirements = array_map( - fn(string $req_package, string $req_version): string => "$req_package:$req_version", - array_keys($v), - array_values($v) - ); - return "--$k=" . implode(',', $requirements); - - case 'version': - // This gets set in the repository metadata itself. - return NULL; - - case 'extra': - // Cannot be set using `composer init`, only `composer config` can. - return NULL; - - default: - throw new \InvalidArgumentException($k); - } - }, array_keys($package), array_values($package))); - } - /** * Adds a path repository. * @@ -623,39 +576,30 @@ class FixtureManipulator { $name = $package['name']; $path_repo_base = \Drupal::state()->get(self::PATH_REPO_STATE_KEY); $repo_path = "$path_repo_base/" . str_replace('/', '--', $name); + $composer_json_path = $repo_path . DIRECTORY_SEPARATOR . 'composer.json'; $fs = new SymfonyFileSystem(); if (!is_dir($repo_path)) { // Create the repo if it does not exist. $fs->mkdir($repo_path); - // Switch the working directory from project root to repo path. - $project_root_dir = $this->dir; - $this->dir = $repo_path; - // Create a composer.json file using `composer init`. - $this->runComposerCommand(['init', ...static::getComposerInitOptionsForPackage($package)]); - // Set the `extra` property in the generated composer.json file using - // `composer config`, because `composer init` does not support it. - foreach ($package['extra'] ?? [] as $extra_property => $extra_value) { - $this->runComposerCommand(['config', "extra.$extra_property", '--json', json_encode($extra_value, JSON_UNESCAPED_SLASHES)]); - } - // Restore the project root as the working directory. - $this->dir = $project_root_dir; - } - - // Register the repository, keyed by package name. This ensures each package - // is registered only once and its version can be updated. - // @todo Should we create 1 repo per version. - $repository = json_encode([ - 'type' => 'path', - 'url' => $repo_path, - 'options' => [ - 'symlink' => FALSE, - 'versions' => [ - $name => $package['version'], + file_put_contents($composer_json_path, json_encode($package, JSON_THROW_ON_ERROR)); + $repository = json_encode([ + 'type' => 'path', + 'url' => $repo_path, + 'options' => [ + 'symlink' => FALSE, ], - ], - ], JSON_UNESCAPED_SLASHES); - $this->runComposerCommand(['config', "repo.$name", $repository]); - + ], JSON_UNESCAPED_SLASHES); + $this->runComposerCommand(['config', "repo.$name", $repository]); + } + else { + $composer_json_data = json_decode(file_get_contents($composer_json_path), TRUE); + // Update the version if needed. + // @todo Should we create 1 repo per version. + if ($composer_json_data['version'] !== $package['version']) { + $composer_json_data['version'] = $package['version']; + file_put_contents($composer_json_path, json_encode($composer_json_data, JSON_THROW_ON_ERROR)); + } + } return $repo_path; } @@ -683,8 +627,17 @@ class FixtureManipulator { } // Update all the repos in the composer.json file to point to the new // repos at the absolute path. - $composer_json = file_get_contents($this->dir . '/composer.json'); - file_put_contents($this->dir . '/composer.json', str_replace('../path_repos/', "$path_repo_base/", $composer_json)); + $json_data = json_decode(file_get_contents($this->dir . '/composer.json'), TRUE); + $composer_json_needs_update = FALSE; + foreach ($json_data['repositories'] as &$existing_repo_data) { + if (is_array($existing_repo_data) && isset($existing_repo_data['url']) && str_starts_with($existing_repo_data['url'], '../path_repos/')) { + $composer_json_needs_update = TRUE; + $existing_repo_data['url'] = str_replace('../path_repos/', "$path_repo_base/", $existing_repo_data['url']); + } + } + if ($composer_json_needs_update) { + file_put_contents($this->dir . '/composer.json', json_encode($json_data, JSON_THROW_ON_ERROR)); + } $this->runComposerCommand(['install']); } diff --git a/pcre.ini b/pcre.ini new file mode 100644 index 0000000000..0c5780afaf --- /dev/null +++ b/pcre.ini @@ -0,0 +1,8 @@ +# This file is used on Drupal CI because Composer occasionally dies with +# PCRE_JIT_STACKLIMIT_ERROR during certain test cases, and there is no insight +# into where the failure is happening, or why. This has only been observed on +# Drupal CI. Since the PCRE engine's JIT is not strictly necessary to the +# functioning of the Automatic Updates module, this file disables the PCRE JIT +# as a workaround. +# @see drupalci.yml +pcre.jit = 0 diff --git a/scripts/src/Converter.php b/scripts/src/Converter.php index 36fbc8f872..0bdb88655a 100644 --- a/scripts/src/Converter.php +++ b/scripts/src/Converter.php @@ -72,6 +72,7 @@ class Converter { 'drupalci.yml', 'README.md', '.git', + 'pcre.ini', 'composer.json', '.gitattributes', '.gitignore', -- GitLab