Ocramius / PackageVersions

:package: Composer addon to efficiently get installed packages' version numbers
MIT License
3.22k stars 67 forks source link

Error when using Composer 1.6.4 with PHP 7.0 #64

Closed vasily-kartashov closed 6 years ago

vasily-kartashov commented 6 years ago

Running composer update ends with the following error

PHP Fatal error:  Uncaught TypeError: Return value of PackageVersions\Installer::activate() must be an instance of PackageVersions\void, none returned in /var/www/php/vendor/ocramius/package-versions/src/PackageVersions/Installer.php:62
Stack trace:
#0 phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(236): PackageVersions\Installer->activate(Object(Composer\Composer), Object(Composer\IO\ConsoleIO))
#1 phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(205): Composer\Plugin\PluginManager->addPlugin(Object(PackageVersions\Installer))
#2 phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(261): Composer\Plugin\PluginManager->registerPackage(Object(Composer\Package\CompletePackage))
#3 phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(76): Composer\Plugin\PluginManager->loadRepository(Object(Composer\Repository\InstalledFilesystemRepository))
#4 phar:///usr/local/bin/composer/src/Composer/Factory.php(384): Composer\Plugin\PluginManager->loadInstalledPlugins( in /var/www/php/vendor/ocramius/package-versions/src/PackageVersions/Installer.php on line 62

Fatal error: Uncaught TypeError: Return value of PackageVersions\Installer::activate() must be an instance of PackageVersions\void, none returned in /var/www/php/vendor/ocramius/package-versions/src/PackageVersions/Installer.php:62
Stack trace:
#0 phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(236): PackageVersions\Installer->activate(Object(Composer\Composer), Object(Composer\IO\ConsoleIO))
#1 phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(205): Composer\Plugin\PluginManager->addPlugin(Object(PackageVersions\Installer))
#2 phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(261): Composer\Plugin\PluginManager->registerPackage(Object(Composer\Package\CompletePackage))
#3 phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(76): Composer\Plugin\PluginManager->loadRepository(Object(Composer\Repository\InstalledFilesystemRepository))
#4 phar:///usr/local/bin/composer/src/Composer/Factory.php(384): Composer\Plugin\PluginManager->loadInstalledPlugins( in /var/www/php/vendor/ocramius/package-versions/src/PackageVersions/Installer.php on line 62
Ocramius commented 6 years ago

You are running it on PHP 7.0.* instead of 7.1+

vasily-kartashov commented 6 years ago

Not sure if it's for you or composer team, but updating composer from 1.6.3 to 1.6.4 now broke the build because of the :void return type. Cannot see anywhere on the composer's website that PHP 7.0 is not supported.

Thanks

Ocramius commented 6 years ago

The problem here is that the PackageVersions plugin is installed in the project you currently have open (or as global dependency somewhere), and you try running it against 7.0.

vasily-kartashov commented 6 years ago

What does phar:// protocol mean in this case? I presumed the plugin was compiled into composer.phar? We are taking about a clean vagrant provisioning, i.e. no other composer plugins are explicitly installed by provisioning. The installation routine is this https://getcomposer.org/download/

Ocramius commented 6 years ago

No, the plugin is on your system, not in phar:// (contents of composer.phar).

The path of this plugin is /var/www/php/vendor/ocramius/package-versions/src/PackageVersions/Installer.php in your case.

vasily-kartashov commented 6 years ago

Thank you, much appreciated.

pablorsk commented 6 years ago

Hi @vasily-kartashov, I have the same problem. The problem is not composer, it's your package.json.

If you solve the problem, can you post the solution? If you don't, can you paste your composer.json?

Ocramius commented 6 years ago

@pablorsk please open a new issue with a detailed description of what you are doing

pablorsk commented 6 years ago

Thanks @Ocramius. I dont really sure if is a bug. This is how can I reproduce the error.

(php version is 7.1)
composer install
(downgrade to php 7.0)
composer install
Fatal error: Uncaught TypeError: Return value of PackageVersions\Installer::activate() must be an instance of PackageVersions\void, none returned in /app/vendor/ocramius/package-versions/src/PackageVersions/Installer.php:62
Stack trace:
#0 phar:///data/bin/composer/src/Composer/Plugin/PluginManager.php(236): PackageVersions\Installer->activate(Object(Composer\Composer), Object(Composer\IO\ConsoleIO))
#1 phar:///data/bin/composer/src/Composer/Plugin/PluginManager.php(205): Composer\Plugin\PluginManager->addPlugin(Object(PackageVersions\Installer))
#2 phar:///data/bin/composer/src/Composer/Plugin/PluginManager.php(261): Composer\Plugin\PluginManager->registerPackage(Object(Composer\Package\CompletePackage))
#3 phar:///data/bin/composer/src/Composer/Plugin/PluginManager.php(76): Composer\Plugin\PluginManager->loadRepository(Object(Composer\Repository\InstalledFilesystemRepository))
#4 phar:///data/bin/composer/src/Composer/Factory.php(384): Composer\Plugin\PluginManager->loadInstalledPlugins()
#5 phar:///data/bin/composer/sr in /app/vendor/ocramius/package-versions/src/PackageVersions/Installer.php on line 62

I think is not a bug, but was very difficult to detect it. :thinking: If you like, I can create the issue for a possible fix to show errors instead of a fatal error.

Real scenario Off course, I don't have any downgrade, they're docker machines with different PHP versions (7.0 and 7.1). They shares vendor dir, then when I exit from PHP7.1 machine and get into PHP7.0 machine, composer breaks down. The only solution is to delete vendor folder content (or check if Ocramius/PackageVersions is used on global)

Ocramius commented 6 years ago

Ah, this is normal behaviour though. Do you have a composer.lock?

pablorsk commented 6 years ago

Yes @Ocramius, but with or without composer.lock the problem persists. The only solution (for now) is "don't share vendor folder between machines".

Ocramius commented 6 years ago

That should already be the case: vendor should be installed, not copied, as that guarantees that dependencies do work on different machines

Majkl578 commented 6 years ago

The only solution (for now) is "don't share vendor folder between machines".

You should share vendor/ that is installed according to your lowest required PHP version, otherwise it's not portable. It should be enforced it by using config.platform.php in composer.json.

dzuelke commented 6 years ago

Alright so, this is still a bug I think that needs fixing.

For instance, I have a project that has this package as a dependency; it's installed inside vendor/.

If I now do composer config vendor-dir on that project using PHP 7.0, I get the crash.

I realize that a composer install won't work with PHP 7.0; this is, in my case, during Heroku's bootstrapping process, where PHP 7.0 and Composer are used to determine what "real" version of PHP to install.

Of course this is happening only to customers who have committed vendor/ to Git, but some people just do that... :(

Ocramius commented 6 years ago

@dzuelke does Heroku use the composer CLI to determine the version? Any way we can reproduce it in autonated tests?

dzuelke commented 6 years ago

Heroku downloads Composer as well as a minimal version of PHP (currently 7.0.30, but that's not the point; this incompatibility could also be in the other direction with a newer version) for bootstrapping, then extracts all platform dependencies from composer.lock, writes a "platform" composer.json, and uses a custom Composer installer to install PHP and all extensions from a custom "platform" repository (that step is then really just a composer install with the generated "platform" composer.json, in .heroku/php).

Sounds a little excessive, but it's the only way to reliably get people the runtimes and extensions their app will composer install with.

But my point was that this package here should probably not break a composer config … call, right? ;)

Ocramius commented 6 years ago

should probably not break a composer config

That's a completely separate issue then, and tbh I wouldn't expect composer to run scripts during composer config :|

Can anybody open an issue with a reproducer tho? I can't do much without the exact scenario that is broken...

dzuelke commented 6 years ago

It doesn't run scripts, but because composer.json has this package as a dependency, and because this package is a Composer plugin, it gets loaded, and activate() is called, leading to the TypeError.

You can reproduce this simply by having e.g. a fully php72 $(which composer) installed doctrine/doctrine-migrations-bundle:^1.3, and then running php70 $(which composer) config.

Of course php70 $(which composer) install should fail, but not config or status, right?

Basically, because this package is a Composer plugin, it needs to support older versions of PHP than you probably would like ;)

Ocramius commented 6 years ago

but not config or status, right?

I'm conflicted here: you produce a project artifact with a newer PHP version, then this gets downgraded (post-install), and that crashes.

To me, this is perfectly normal, even for config and status crashing: that project is no longer usable with other environment versions.

Still, if I wanted to allow this package to run that way, I'd make the plugin activation bits un-typed.

it needs to support older versions of PHP than you probably would like ;)

The "needs" bit is exactly where I reserve my own right to say "no" :-P

dzuelke commented 6 years ago

Is this maybe something Composer should handle (by catching the error and selectively disabling the plugin) for commands such as composer config and friends? @naderman and @seldaek, what's your take on this?

naderman commented 6 years ago

I don't think this is something we have any interest in doing automatically or supporting. If you have a PHP 7.1+ plugin installed, it will error on PHP 7.0. If you want to run it on PHP 7.0, run without the plugin.

dzuelke commented 6 years ago

Yeah @naderman but you can't even run diagnose or validate or self-update if a project like that is the current working dir...

Ocramius commented 6 years ago

Yeah, because the listeners are regisered upfront, I suppose. The alternative would be to make all listeners (somehow) lazy

Seldaek commented 6 years ago

@dzuelke you can run these commands with --no-plugins. If you don't expect a plugin is required for these commands to function correctly in your context, it's safer to disable them. 1.7-RC had a regression where disabling plugins failed, but 1.7.0 should do it fine.

dzuelke commented 6 years ago

I can, @Seldaek, but what about the average user who's just trying to do a self-update in an attempt at fixing "those weird Composer errors" they don't quite realize the root cause of?

I agree it's a rare situation though, but it happens, as evidenced by this ticket ;)

cmtatro commented 5 years ago

I know this is an old topic, but I am seeing that the documentation on the installation for the vim-plugin page says php7.0, but this ticket proves that you need 7.1 to make it work. Can we alter this page to make it reflect either the composer install --no-plugins or bump the recommendation to PHP7.1

BUG: Current manual install procedure does not work.

If you need to install the dependencies manually, then:

$ cd ~/.vim/plugged/phpactor
$ composer install

https://phpactor.github.io/phpactor/vim-plugin.html

Ocramius commented 5 years ago

Both PHP 7.0 and 7.1 are EOL'd and not relevant anymore: please upgrade.

Locking here: there is absolutely no reason to discuss 7.0 or 7.1 support anymore.