-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Description
With an empty composer.json:, when I run these commands:
composer global require "laravel/installer=~1.1"
composer global require wp-cli/wp-cli
I get this output:
Using version ^0.23.1 for wp-cli/wp-cli
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.
Problem 1
- Installation request for wp-cli/wp-cli ^0.23.1 -> satisfiable by wp-cli/wp-cli[v0.23.1].
- Conclusion: remove symfony/config v2.2.11
- Conclusion: don't install symfony/config v2.2.11
(Error output truncated)
And I expected this to happen:
Installing commandline tools following recommended installation procedures on the specified project's installation instructions page should succeed, and not be subject to variable failures depending on which other projects were installed first.
Analysis
The Composer documentation says:
Composer is not a package manager in the same sense as Yum or Apt are. Yes, it deals with "packages" or libraries, but it manages them on a per-project basis, installing them in a directory (e.g. vendor) inside your project. By default it does not install anything globally. Thus, it is a dependency manager. It does however support a "global" project for convenience via the global command.
However, the design of Composer is clearly geared towards the per-project dependency management model. The global
keyword creates a "global" project as a convenience; however, the users of this keyword do not expect that the projects they install in this way should all become part of a single project. Each project installed has its own set of requirements, and its own expectation that these should be managed in a self-consistent way, and yet, if certain projects are unceremoniously combined, then unexpected project conflicts may be encountered. These errors are difficult for beginning Composer users to understand, and they return with them to the maintainers of the project they are trying to install.
Suggested Solutions
In the short term, stop promoting the use of composer global require
as an installation method for global cli tools, and instead, actively discourage its use. As an alternative, users should use composer require
to install each commandline tool to its own local project, and manage their $PATH or binaries manually (e.g. by creating symlinks from a bin directory already in the $PATH).
In the mid-to-short term, the Composer global
keyword should be deprecated (e.g. add warning messages when it is executed), and then either removed or fixed.
If the global
keyword is retained, it should not continue to be used to manage a "global" project, as doing this is untenable. Instead, it should be re-cast as (or replaced by) a mechanism for managing a global bin
directory. This is the primary use-case for it right now; it is feasible and practical to combine bin
directories from disparate projects without causing conflict, as long as each project had its own vendor
directory -- as is the fundamental assumption for top-level Composer projects.
For example, a "global" but isolated project could be installed to ~/.composer/global/[something]
; its vendor
and bin
directories would appear in their usual locations, and the contents of the ~/.composer/global/[something]/bin
directory could be mirrored (via symlink) in ~/.composer/vendor/bin
or, perhaps a better option would be simply ~/.composer/bin
. There are various ways that the string [something]
could be chosen; the most straightforward would be simply org/project
(although this means that long paths such as ~/.composer/global/org/project/vendor/org/project
would exist).
One complication of the proposed solution is that further management of the "global" projects would be more complicated. With the global
keyword, it is possible to run composer global require foo/foo
, followed later by composer global require foo/extension
, and the extension will end up in the same project as the top-level foo/foo project. This is an uncommon use-case, though; usually, the global
keyword's only use is for the installation of atomic global commandline tools.
I could work on a PR to provide global bin directory management, if there is some agreement on how these commands should best work.