Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin installer throws Unable to determine the base path during composer update #10

Open
matfish2 opened this issue Nov 4, 2021 · 2 comments

Comments

@matfish2
Copy link

matfish2 commented Nov 4, 2021

Description

When installing plugins, sometimes composer update/install will abort with the following error:

  [craft\composer\InvalidPluginException]                                         
  Couldn't install some/plugin: Unable to determine the base path  

Or

 [craft\composer\InvalidPluginException]                                         
  Couldn't install some/plugin: Unable to determine the Plugin class

Steps to reproduce

Unfortunately that seems to happen only on some environments, and even then inconsistently, so it might be difficult to reproduce.
I'm running composer update from a laravel homestead VM.
Linux homestead 5.4.0-81-generic #91-Ubuntu SMP Thu Jul 15 19:09:17 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

I have traced the error to plugin-installer/Installer.php:124-131
both $class and $basePath are null, because they are not included in the $extra = $package->getExtra(); response.

I have run:

rm -rf vendor
rm composer.lock
composer clearcache
composer install

But to no avail.

I have noticed this bug was reported on some individual plugins, but it seems like it's a craft issue, since I'm getting this for multiple plugins.

Additional info

  • Craft version: 3.7.19
  • PHP version: 8.0.9
  • Database driver & version: MySQL 5.5.5
  • Composer version: 2.1.11
  • Plugins & versions:
  • "fortrabbit/craft-copy": "^1.0",
    "craftcms/redactor": "2.8.8",
    "sebastianlenz/linkfield": "^1.0",
    "nystudio107/craft-seomatic": "^3.4"
@brandonkelly brandonkelly transferred this issue from craftcms/cms Nov 4, 2021
@brandonkelly
Copy link
Member

both $class and $basePath are null, because they are not included in the $extra = $package->getExtra(); response.

If extra.class is not defined within the plugin’s composer.json file, then the installer will look for a Plugin.php file within each of the plugin’s autoload paths:

// If we're still looking for the primary Plugin class, see if it's in here
if ($class === null && file_exists($path . '/Plugin.php')) {
$class = $namespace . 'Plugin';
}

If it can’t find one, you will get the “Unable to determine the Plugin class” error.

The base path is then set to the directory that contains the Plugin class:

// If we're still looking for the base path but we know the primary Plugin class,
// see if the class namespace matches up, and the file is in here.
// If so, set the base path to whatever directory contains the plugin class.
if ($basePath === null && $class !== null) {
$n = strlen($namespace);
if (strncmp($namespace, $class, $n) === 0) {
$testClassPath = $path . '/' . str_replace('\\', '/', substr($class, $n)) . '.php';
if (file_exists($testClassPath)) {
$basePath = $this->_path($vendorDir, $cwd, dirname($testClassPath));
}
}
}
}

I’m not really sure what to make of this not working inconsistently. Is there any chance we can get SSH access to an environment where this occurs? If so, please send the connection info to [email protected].

@matfish2
Copy link
Author

matfish2 commented Nov 5, 2021

I've narrowed it down to lines 335-338
$testClassPath is set to /home/vagrant/code/mcl-craft/vendor/nystudio107/craft-seomatic/src/Seomatic.php
Which is correct.
However, the file_exists check returns false.

Commenting out the if statement on line 336, fixes the issue for me.

One more option that worked was adding sleep(1) before line 336. It appears to be a syncing of shared folders issue then, though I'm running composer from the VM, not the Windows host, so I fail to see how it is related.

In conclusion a suggested fix would be something like:

$attempts = 0;

do {
  if ($attempts>0) {
      sleep(1);
  }
  
  if (file_exists($testClassPath)) {
      $basePath = $this->_path($vendorDir, $cwd, dirname($testClassPath));
  }

  $attempts++;
} while (!$basePath && $attempts <= 2);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants