Skip to content

Add a require-bin or require-tools section to reduce the need for composer global #5390

@greg-1-anderson

Description

@greg-1-anderson

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions