"core_version_requirement key must be present" on core modules on Windows

Created on 27 August 2023, 10 months ago
Updated 4 October 2023, 9 months ago

Problem/Motivation

We have discovered, that it is no longer possible to install Drupal 10 on Windows machine when using 10.2.x-dev (11.x branch). It seems like something has changed and the paths to core modules are not resolved correctly, which is causing the InfoParser to complain that core modules does not have core_version_requirement set (which should not be the case). See:

Drupal\Core\Extension\InfoParserException: The 'core_version_requirement' key must be present in D:\htdocs\d10test\core/modules/mysql/mysql.info.yml in Drupal\Core\Extension\InfoParserDynamic->parse() (line 67 of core\lib\Drupal\Core\Extension\InfoParserDynamic.php).

Drupal\Core\Extension\InfoParserDynamic->parse('D:\htdocs\d10test\core/modules/mysql/mysql.info.yml') (Line: 22)
Drupal\Core\Extension\InfoParser->parse('D:\htdocs\d10test\core/modules/mysql/mysql.info.yml') (Line: 210)
Drupal\Core\Extension\DatabaseDriver->getModuleInfo() (Line: 160)
Drupal\Core\Extension\DatabaseDriver->getAutoloadInfo() (Line: 95)
Drupal\Core\Extension\DatabaseDriver->load() (Line: 110)
Drupal\Core\Extension\DatabaseDriver->getInstallTasks() (Line: 110)
Drupal\Core\Extension\DatabaseDriverList->getInstallableList() (Line: 530)
system_requirements('install') (Line: 907)
drupal_check_profile('minimal') (Line: 2084)
install_check_requirements(Array) (Line: 1098)
install_verify_requirements(Array) (Line: 707)
install_run_task(Array, Array) (Line: 578)
install_run_tasks(Array, NULL) (Line: 121)
install_drupal(Object) (Line: 48)

This is only problem on 11.x branch. The last 10.1.x can be installed without problems. I do not think this is related to 🌱 [policy, no patch] Drop support for Windows in production Needs review .

Steps to reproduce

Try to install 11.x (10.2.x-dev) on windows (xampp or another environment).

Proposed resolution

Find the problem and fix the issue.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

πŸ› Bug report
Status

Fixed

Version

11.0 πŸ”₯

Component
InstallΒ  β†’

Last updated 1 day ago

No maintainer
Created by

πŸ‡ΈπŸ‡°Slovakia poker10

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @poker10
  • Status changed to Needs review 10 months ago
  • last update 10 months ago
    30,060 pass
  • πŸ‡ΈπŸ‡°Slovakia poker10

    I would say this is caused by ✨ Introduce database driver extensions and autoload database drivers' dependencies Fixed , with the introduction of a new getModuleInfo() function.

    There is a DIRECTORY_SEPARATOR used, which is \ on windows, but in the InfoParserDynamic class there is still / hardcoded (see /core/):

          if (!isset($parsed_info['core_version_requirement'])) {
            if (str_starts_with($filename, 'core/') || str_starts_with($filename, $this->root . '/core/')) {
              // Core extensions do not need to specify core compatibility: they are
              // by definition compatible so a sensible default is used. Core
              // modules are allowed to provide these for testing purposes.
              $parsed_info['core_version_requirement'] = \Drupal::VERSION;
            }
          }
    

    So the path D:\htdocs\d10test\core/modules/mysql/mysql.info.yml does not pass on check str_starts_with($filename, $this->root . '/core/').

    Let's try a patch which simply changes the hardcoded slash for DIRECTORY_SEPARATOR.

  • πŸ‡ΈπŸ‡°Slovakia poker10

    Not sure if we can test this windows-only issue somehow, so will keep this NR for other feedback. Thanks!

    Tested the patch also manually and it fixed the error.

  • πŸ‡ΈπŸ‡°Slovakia poker10
  • Status changed to Needs work 10 months ago
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Anyway to get a test case showing the issue added?

    @shweta__sharma can I ask what that tag is meant for?

    Thanks!

  • Status changed to Needs review 10 months ago
  • πŸ‡ΈπŸ‡°Slovakia poker10

    I briefly searched the issue queue for Windows issues from the past, but was unable to figure out if/how to test this windows-only issue in our tests (if it is possible, any help will be appreciated and feel free to re-set the Needs tests tag again). Therefore also upon the discussion with @smustgrave on Slack, I am moving this back to Needs review.

    I am also changing the priority to major, as this bug prevents Drupal 10.2.x from being installed on Windows.

  • Status changed to RTBC 10 months ago
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Thanks for digging @poker10. Going to mark then.

  • πŸ‡³πŸ‡±Netherlands Spokje

    As a Windows user, I can confirm the problem and the patch solving the problem.

    (In fact I came up independently with the exact same one to get core installing and/or running a test. Just wasn't sure it was something that would be eligible for an official patch on here, since Windows only)

  • πŸ‡¬πŸ‡§United Kingdom catch
    +++ b/core/lib/Drupal/Core/Extension/InfoParserDynamic.php
    @@ -51,7 +51,7 @@ public function parse($filename) {
    +        if (str_starts_with($filename, 'core/') || str_starts_with($filename, $this->root . DIRECTORY_SEPARATOR . 'core/')) {
    

    Possibly silly question - why doesn't the trailing slash also need to use directory separator?

    We've got an issue open to drop support for Windows on production, but even if that gets agreed, issues like this would still be valid fwiw.

  • πŸ‡ΈπŸ‡°Slovakia poker10

    Possibly silly question - why doesn't the trailing slash also need to use directory separator?

    I would say that this is caused by the fact, that the paths to extensions are build by ExtensionDiscovery class. This class has scanDirectory() method, which is building the $pathname for each Extension object (this $pathname is used in InfoParserDynamic::parse() calls subsequently).

    And the scanDirectory() method is using this code:

        $absolute_dir = ($dir == '' ? $this->root : $this->root . "/$dir");
    
        // Use Unix paths regardless of platform, skip dot directories, follow
        // symlinks (to allow extensions to be linked from elsewhere), and return
        // the RecursiveDirectoryIterator instance to have access to getSubPath(),
        // since SplFileInfo does not support relative paths.
        $flags = \FilesystemIterator::UNIX_PATHS;
        $flags |= \FilesystemIterator::SKIP_DOTS;
        $flags |= \FilesystemIterator::FOLLOW_SYMLINKS;
        $flags |= \FilesystemIterator::CURRENT_AS_SELF;
        $directory_iterator = new \RecursiveDirectoryIterator($absolute_dir, $flags);
    

    See the hardcoded forward slash in $absolute_dir. Because of that, you will end up with paths like these D:\htdocs\d10test/core/modules/action/action.info.yml from the *SplFileInfo*pathName.

    The first part (D:\htdocs\d10test) is taken from $this->root, which is based on \Drupal::root(), which is computed by dirname(), which returns a path with backslashes on Windows.

    The second part (core/modules/action/action.info.yml) is taken from RecursiveDirectoryIterator, which has forced unix slashes.

  • πŸ‡ΈπŸ‡°Slovakia poker10

    And yes, the ExtensionDiscovery::scanDirectory() is using only this for $pathname:

    $pathname = $dir_prefix . $fileinfo->getSubPathname();
    

    So it will be core/modules/mysql/mysql.info.yml.

    But the new DatabaseDriver::getModuleInfo() is adding $this->root as well:

      private function getModuleInfo(): void {
        if (!isset($this->info)) {
          $infoParser = new InfoParser($this->root);
          $this->info = $infoParser->parse($this->root . DIRECTORY_SEPARATOR . $this->getModule()->getPathname());
        }
      }
    

    $this->root is D:\htdocs\d10test
    DIRECTORY_SEPARATOR is \
    $this->getModule()->getPathname() is core/modules/mysql/mysql.info.yml (see the previous comment)

    So it seems to me that this is causing the paths with backwards and forwards slashes.

  • last update 10 months ago
    30,063 pass
  • last update 10 months ago
    30,130 pass
  • last update 10 months ago
    30,135 pass
  • last update 10 months ago
    30,136 pass
  • last update 10 months ago
    30,136 pass
  • 25:10
    23:59
    Running
  • last update 10 months ago
    30,146 pass
  • last update 10 months ago
    30,150 pass
  • last update 10 months ago
    30,154 pass
  • last update 10 months ago
    30,161 pass
  • last update 9 months ago
    30,156 pass, 2 fail
  • last update 9 months ago
    30,168 pass
  • πŸ‡³πŸ‡±Netherlands Spokje

    Know random test RandomTest failure πŸ› Random test fail in Drupal\Tests\Component\Utility\RandomTest::testRandomMachineNamesUniqueness Needs work (and yes, I have been waiting weeks to make that crappy joke), back to RTBC.

  • last update 9 months ago
    30,168 pass
  • last update 9 months ago
    30,205 pass
  • last update 9 months ago
    30,204 pass, 2 fail
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Believe to be unrelated

  • last update 9 months ago
    30,208 pass
  • last update 9 months ago
    30,360 pass
  • last update 9 months ago
    30,348 pass, 2 fail
  • Status changed to Needs work 9 months ago
  • πŸ‡³πŸ‡±Netherlands Spokje

    It would be really nice to get this one in, so I don't have to apply it manually every time I want to install core or run a test locally

  • Status changed to RTBC 9 months ago
  • πŸ‡³πŸ‡±Netherlands Spokje
  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ
    +++ b/core/lib/Drupal/Core/Extension/InfoParserDynamic.php
    @@ -51,7 +51,7 @@ public function parse($filename) {
    -        if (str_starts_with($filename, 'core/') || str_starts_with($filename, $this->root . '/core/')) {
    +        if (str_starts_with($filename, 'core/') || str_starts_with($filename, $this->root . DIRECTORY_SEPARATOR . 'core/')) {
    

    The mix of hard coded / and DIRECTORY_SEPARATOR feels really icky here. Really hard to explain. Like If we changed it to
    str_starts_with($filename, $this->root . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR it would break again on windows.

    I wonder if instead we should be changing \Drupal\Core\Extension\DatabaseDriver::getModuleInfo() instead to do:

        if (!isset($this->info)) {
          $infoParser = new InfoParser($this->root);
          $this->info = $infoParser->parse($this->getModule()->getPathname());
        }
    

    As that would be inline with other calls to \Drupal\Core\Extension\InfoParserDynamic::parse() for extension listing services.

    I wonder why $filename is sometimes an absolute path.

    I think it'd be good to see if we could somehow make this look a bit better.

    • xjm β†’ committed 5ce054a4 on 11.x
      Issue #3383616 by poker10, Spokje, catch: "core_version_requirement key...
    • xjm β†’ committed 67aaa20d on 10.1.x
      Issue #3383616 by poker10, Spokje, catch: "core_version_requirement key...
  • Status changed to Fixed 9 months ago
  • πŸ‡ΊπŸ‡ΈUnited States xjm

    I had exactly the same question as #10, and @poker10 explained the reasoning quite well. Adding credit for @catch for posing a helpful question, and @Spokje for jokes. (It's actually for the manual testing, but let's pretend it's the joke.)

    Committed to 11.x, and cherry-picked to 10.1.x as a patch-eligible, major-borderline-critical bugfix.

    Thanks everyone!

  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

    I think this change might cause more problems though. Because maybe some other custom code that is running on windows as worked around the code as it is Drupal 10.0.x. And now it fails. And the mixture of slashes here is likely to cause more bugs in the future. I think the real issue here is that we should have fixed the new code in \Drupal\Core\Extension\DatabaseDriver::getModuleInfo() as per #20. I thought I'd set this one to needs work. The only reason we accept a full path in parse() is for testing. Which I might have introduced and now regret.

  • Status changed to Needs review 9 months ago
  • last update 9 months ago
    30,328 pass, 1 fail
  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

    I think we should revert this from 10.1.x and commit the following patch to 11.x for the quick fix. And then open a follow-up to discuss how we should improve \Drupal\Core\Extension\InfoParserDynamic::parse() so that the paths are more filesystem agnostic.

  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

    As an example of stuff that would pass on Windows before this change but now will not see core/tests/Drupal/KernelTests/Config/DefaultConfigTest.php where we do
    $file_name = DRUPAL_ROOT . '/core/modules/system/tests/themes/' . $name . '/' . $name . '.info.yml';

  • πŸ‡¬πŸ‡§United Kingdom catch

    If #25 works that looks fine as a quick fix. Definitely we should try to minimise the mix of slashes, it's very confusing just reading it, let alone trying to figure out what the practical effects might be.

  • last update 9 months ago
    30,316 pass, 3 fail
  • last update 9 months ago
    30,361 pass
  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

    So #25 is failing because PHPUnit tests don't set the working directory to Drupal root but extension discovery including now database driver discovery assumes that you are in Drupal root. There are other unit tests that set the working directory for this reason so UrlConversionTest can do the same. I think we might consider throwing an exception in \Drupal\Core\Extension\DatabaseDriver::getModuleInfo() if $this->info is an empty array as that means an info file does not exist which is not really valid.

  • πŸ‡ΊπŸ‡ΈUnited States xjm
    +++ b/core/tests/Drupal/Tests/Core/Database/UrlConversionTest.php
    @@ -27,6 +27,8 @@ class UrlConversionTest extends UnitTestCase {
    +    // This unit relies on reading files relative to Drupal root.
    

    This unit test maybe? Otherwise it sounds like a robot's version of first person.

    Is #29 intended for both 11.x and 10.1.x? (And wouldn't it have been better to just revert it first anyway?)

  • last update 9 months ago
    30,362 pass
  • πŸ‡ΈπŸ‡°Slovakia poker10

    Thanks all for your effort with this issue! I have tested the patch #29 and it seems to work on Windows as the patch #2. Given the severity of this (unable to install or update 11.x branch on Windows), I think that it would be good to have one of these quick fixes committed (#2 or this new approach). @alexpott raised some concerns about the patch #2 in #24 πŸ› "core_version_requirement key must be present" on core modules on Windows Needs review , so in that case it would probably be safer to commit the later one.

    Is #29 intended for both 11.x and 10.1.x? (And wouldn't it have been better to just revert it first anyway?)

    The issue which caused this was committed to 11.x branch only: ✨ Introduce database driver extensions and autoload database drivers' dependencies Fixed , so I think it should be sufficient to commit the fix to the 11.x. And the cleanest way probably will be to revert both commits and commit the patch I am uploading now - it is the same as #29, but without the code being reverted (as it will be reverted separately).

    This unit test maybe? Otherwise it sounds like a robot's version of first person.

    I have also updated this comment in the uploaded patch.

    I think we might consider throwing an exception in \Drupal\Core\Extension\DatabaseDriver::getModuleInfo() if $this->info is an empty array as that means an info file does not exist which is not really valid.

    @alexpott Do you mean here, or in the follow-up?

    Thanks!

  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

    @alexpott Do you mean here, or in the follow-up?

    Definitely a follow-up.

    Yep we can revert #2 from 10.1.x and 11.x and then commit #31. I'll do the reverts and then someone can rtbc this.

  • Status changed to RTBC 9 months ago
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Per #32

  • Status changed to Fixed 9 months ago
  • πŸ‡¬πŸ‡§United Kingdom catch

    Committed/pushed to 11.x, thanks!

    • catch β†’ committed 9698403e on 11.x
      Issue #3383616 by poker10, alexpott, Spokje, catch, xjm: "...
  • πŸ‡ΊπŸ‡ΈUnited States xjm

    I think this still needs that followup filed?

  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.69.0 2024