Plugin installer throws Unable to determine the base path during composer update
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"
both
$classand$basePathare 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:
https://github.com/craftcms/plugin-installer/blob/23ec472acd4410b70b07d5a02b2b82db9ee3f66b/src/Installer.php#L324-L327
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:
https://github.com/craftcms/plugin-installer/blob/23ec472acd4410b70b07d5a02b2b82db9ee3f66b/src/Installer.php#L329-L341
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].
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);