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
Add a require-bin or require-tools section to reduce the need for composer global #5390
Comments
This perfectly reflects the reasons why I never use |
@greg-1-anderson, for that issue, you might also need to have a look at how composer handles global plugins and installers. I tried to explain the problems with the current implementation in #5333. |
I am in favor of deprecating As for proposed solutions, I see no need for any. Most projects that can be installed globally, are also available in Phar form. The latter can easily be "installed" somewhere in your PATH. |
And for your suggested solution of managing several separate projects and linking their bin scripts to a common folder in the path, I suggest you to build this as a separate tool (using the Not that changing the behavior of |
There are still valid use cases for 'global' packages... but since With my Ansible roles, probably 1/3 or more of the issues I get for composer, Node/NPM, and Ruby/gems all have to do with people screwing things up with regard to global vs project installs/dependencies. |
Instead of removing
So people who know how/when to use it won't miss it, and people will (hopefully) stop advising for its use. |
I'd like to chime in on the other side of the spectrum and say that global require saves me a bunch of time very often. If you're using best practices and keeping your main development machine clean, only developing in VMs or containers, you'll never run into this problem, but will allow for lightweight project folders (and better IDE performance to boot), shared testing tools with setups common to your workflow, and more. In short, I see nothing wrong with global because the development environment of every app I'm working on is isolated. I would argue that developing everything on one machine (virtual or not) should be discouraged sooner than discouraging the use of I do agree with @naroga though in that there should be a warning saying "installing globally might create conflicting dependencies", but without the "is not recommended" part. |
So it is not a global installation ;-) Running a docker container with a modified |
Totally agree. It would be amazing to have each |
There is a use-case where Predominantly, the projects found in the top Google search results that recommend the use of There are only a few instances where For those who like the convenience of |
Since folks love New Proposed Solution
These flags could be named in other ways, of course, e.g. a single flag with a value indicating "shared" vs. "isolated". Whatever flag name or names is/are used, they should be chosen to avoid conflicts with flags used in other Composer commands that may be called via |
I tested CGR and was quite happy with how it worked. I tried to encourage others to do the same and provide feedback (should yield a user or two I hope), but I think it's a good solution, if However, the |
Why does this problem exist in Composer and not in similar tools like NPM. What do they do differently here? |
Dependencies in composer are all in the same set (flat structure, basically), while in NPM, since JS has no globally defined types, each package requires all its dependencies as sub-dependencies, recursively. |
There might be use-cases between Also, these concerns about dependency conflicts with cli tools are also valid for local projects (for the record I had also started a plugin for this : https://github.com/bamarni/composer-bin-plugin). |
I'd suggest:
|
If we added --no-dev could apply to |
Some concerns if we go into this direction :
I think this would require some massive changes as composer.json has always been about describing a single set of dependencies, and here we'd have multiple. So changing the json schema for this sounds very unrealistic imo. It has also been rejected not long ago (#4381). |
Yes, makes sense; we should try to move forward without composer.json changes. |
A lot of discussion focuses on resolution of incompatible dependencies; should we also support aliasing to support different versions of a binary tool?
|
Conceptually as well as practically, this is a very different from creating isolated projects for the purposes of installing packages and their dependencies in isolation. I'd argue this feature has nothing to do with What the cgr script does is something very distinct from this - it's actually managing creation, updates and removal of isolated projects. I would therefore like to propose an entirely different set of commands, distinct from
The Running the The Thoughts? |
I think is a bit confusing see: "require" and "get" maybe is better use "require isolated project/project" or "require general project/rpls" |
Overloading the |
I agree with @mindplay-dk here. While I am uncertain what the best and clearest names for these commands should be, that is just a semantic issue; I do think that the "install application" operation needs to be logically separated (i.e., implemented as a separate command) from |
Thinking more about this though, it occurs to me there might be cases where you want to do something different to one of your isolated projects. For example, if you've installed some tool like, say, phpunit or phpmd, it's not unthinkable you might want to install an optional plugin of some sort as well, is it? So maybe this actually needs to work more like |
Yes, that is true -- an application that you install globally might want to have plugins as well. I have been considering an interim command in
In other words, an In the meantime, folks can always use the alternate solution shown on the |
I found this post while trying to troubleshoot some problems I was having installing a couple of command-line tools (PHP CodeSniffer and PHPCompatibility) via Composer. But if I'm understanding this correctly, Composer should not be used for things like that (i.e. tools that you want to be able to use on a variety of projects), only for specific projects? I'm a little confused by this - the whole reason I even have Composer installed is that it was required in order to install another tool recently, Mixed Content Scan, which like the others above is not project-specific. Both of the ones I've been trying to install today give Composer installation instructions, and don't seem like the sort of thing you would want to install separately for every project you work on - I mean, at a glance, I have 40 local Git repositories for various projects, and I certainly don't want to have to install every useful tool 40 times over! Should I not be using Composer to install any sort of commands that I want to be able to use globally? Is doing so invariably going to cause some kind of problems? |
@lynna-freeform Yes, your summary is correct. A lot of global php commandline tools recommend using |
For the record there is also my plugin : https://github.com/bamarni/composer-bin-plugin It has a different approach than cgr. While it might be less opinionated / user-friendly, it also solves more use cases :
|
bamarni/composer-bin-plugin is very nice; I added a link to it from the cgr README. I see development on bamarni/composer-bin-plugin started a few weeks before this issue was posted. If I had known about it, I might not have bothered to write cgr. |
There seems to be quite the variety of solutions building up around this: With the explosion of PHP CLI tools in the past couple years (primarily as PHARs), is the simplest solution not for Composer to simply have something like a |
Having to pick a third-party tool for this really is a nuisance. I don't know why there's anything controversial about adding this feature. I'd like to propose a really simple solution: just add an option to define the home folder, and make it accept a relative path. So:
As far as I can tell, the only thing you would need to do is join the This approach is simple, backwards-compatible, has practically zero learning curve, should be very easy to implement, and provides complete freedom to install any combination of tools and plug-ins etc. as needed. I know there's a gazillion tools to address this need already, but I don't even want to choose, much less have to direct users to one or more choices of tools so they can install my tools - and clearly the existence of these tools demonstrates a need. Please, can we get past the FUD and just solve this? |
@mindplay-dk you can already do it inline if you want: COMPOSER_HOME=blaz composer global require ... |
@SamMousa that doesn't "just work" - you'd have to modify your search path every time.
|
Looking through this issue and the various comments on here I think we're actually conflating two key problems, so I'll try and summarize the two main points as I see them and add my opinion where i have one. 1 - What is the purpose of requiring a package "globally" rather than locally in a project?
2 - How can PHP Tools be allowed to internally use libraries in versions which conflict with my project code or other tools I am using?
Analyzing these problemsSo to me it seems like the global command flag could continue to work as-is for global plugins, but we need to provide better solutions for installing PHP tools locally in a project. Global plugins all have to run together in the same process scope as Composer, so they should have all their dependencies analyzed together. But for tools we could strictly discourage the use of global and display warnings when using the command, if we provide better solutions suitable for tools installed on a project level. One potential (partial) solution would indeed be to introduce a new type of require for individual tools, as has been proposed in some comments here. Packages listed in "require-tool" (not sure about the naming) would each be resolved as if they had their own composer.json requiring just them. If the tools have a plugin mechanism and need users to add more packages, we would need to provide a mechanism to group packages to resolve their dependencies together. This solution would not yet resolve the problems with tools which load and execute project code. The only way to avoid conflicts with these would actually be to modify names when writing the tool to disk. So I think our only hope to resolve this is this project: https://github.com/humbug/php-scoper However due to PHP's dynamic nature this does not easily work on every project. So we would need a way to mark packages as compatible for use with this tool in composer.json. Using PHAR files does not by itself fix anything, because the classnames would still conflict at runtime just the same. PHAR files are a workaround for our current lack of a "require-tool" option, but it doesn't fix runtime conflicts. We could enforce the installation of "require-tool" as phar files, but I'm not sure if there's really a benefit to doing that? ConclusionsWe should introduce a new "require-bin" or "require-tool" key in composer.json (potentially a matching -dev pair as well, if we do not want to make assumptions regarding tools and the --no-dev flag). This key should contain groups of packages with version constraints to be resolved independently of the project, so long as all dependencies are marked compatible with humbug/php-scoper. Each tool should be installed into a separate folder vendor/tools/... We should then discourage the use of composer global require for PHP tools and display appropriate warnings. Note, if you paid attention, you'll have noticed this particular proposal for keeping "global" around would still allow you to install tools globally into ~/.composer/vendor/tools/ and potentially even multiple versions at the same time depending on how exactly we define "require-tool"/"require-bin". PHPUnit progress on using php-scoper: sebastianbergmann/phpunit#2015 - sebastianbergmann/phpunit#3086 |
It has been my usage thus far. The best example is
I don't necessarily think the need here is to save a bit of disk space but rather but some commands/tools globally usable. For example:
That said I agree the current implementation/usage is limited. Before extending on the potential solutions, I would like add another angle to the problem. The root of the issue is that Composer is being used as a tool installer in some cases, because it's convenient and we don't have anything better. For example you cannot have
And regardless of how the application is installed, via Composer or as a PHAR, as mentioned above, there is an issue whenever the application will load/execute arbitrary code as there is a risk of conflicts. In light of the above and @naderman analysis of the issue. I think a
IMO this solution would elegantly solve the issue of installing tools/apps via Composer whilst being able to keeping track of them on a project level when desired. Now regarding the last issue of code conflict. I think indeed Humbug PHP-Scoper is the way to go (disclaimer: I am the maintainer of the tool). It is in my opinion not perfect, mostly because:
namespace Acme;
tap(); // is it \tap() or \Acme\tap()?
PHP-Scoper offers a number of ways to overcome those limitations and you will always find a way to make it work regardless of how dirty the code is, but my point is unlike you have a very traditional standard code, it will most likely never achieve the experience of "it works" on the first try. I'm trying very hard to make it as easy as possible, but this is how the language and its limitations are. All of this to say I don't think PHP-Scoper or any similar tool will ever be robust and reliable enough to scope packages on the fly natively by Composer. However one is definitely encourage to use to it:
I think another topic which needs to be discussed is the choice regarding the PHARs. Indeed at least in the solution I've mentioned above, we are talking of having a good integration for PHAR files with Composer. Maybe another approach would be to completely forget about PHARs. If composer can install those tools as libraries, maybe it could install the shims instead. I.e. instead of having:
or:
The scoped code could be uploaded as an artefact with the release and Composer would have a way to understand "this is a shim package, i.e. a code without conflict, pick this one for Indeed right now having a scoped PHAR or a separate a shim packages are both non-trivial amount of work for each maintainers. Publishing the shim package as an artefact still requires the work of making the scoping work, but would remove the burden to deal with PHARs or having a shim package to synchronize. |
I agree that it is a problem that Composer is doing double-duty as both a dependency manager and an installer. Other languages, such as Go, do these options with separate tools. The PHP community doesn't have a uniform installer. I am -1 on using PHP-Scoper / PHP-Parser in Composer due to the limitations described in the comment above. I am +1 on seeing PHP-Scoper, or equivalent function thereof, becoming a standard language feature in a future version of PHP. Under that scenario, then supporting it in a dependency manager or installer would be natural. |
Just to make sure there is no confusion: I suggested a way in which it could make it slightly easier (publishing the scoped content as an artefact - it doesn't have any dependence on the tool used to achieve it neither is there any promise that the code is perfectly scoped either) but the responsibility to scope a library/application is entirely on the maintainer(s). |
This seems to implement exactly what some of you discussed above, have a look at it: https://github.com/tommy-muehle/tooly-composer-script |
See also the discussion in phive about this topic: phar-io/phive#88 |
* Add fix script * Split install-dependencies script for parity with other scripts * Install PHP tools using Composer, running utils/install-phars.sh not necessary any more (We did not do that in the past to avoid clashes between our and their dependencies but this does not seem to be an issue at the moment.) Ideally, composer would fix that on their end: composer/composer#5390 * Use install-dependencies on CI as well * COMPOSER_NO_INTERACTION is now set on CI, instead of manually passing it to every composer commands.
* Add fix script * Split install-dependencies script for parity with other scripts * Install PHP tools using Composer, running utils/install-phars.sh not necessary any more (We did not do that in the past to avoid clashes between our and their dependencies but this does not seem to be an issue at the moment.) Ideally, composer would fix that on their end: composer/composer#5390 * Use install-dependencies on CI as well * COMPOSER_NO_INTERACTION is now set on CI, instead of manually passing it to every composer commands.
Closing in favor of #9636 which is a good summary and has less history to read through. Please subscribe there if you're still interested in this issue. |
With an empty composer.json:, when I run these commands:
I get this output:
(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:
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 usecomposer 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 globalbin
directory. This is the primary use-case for it right now; it is feasible and practical to combinebin
directories from disparate projects without causing conflict, as long as each project had its ownvendor
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]
; itsvendor
andbin
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 simplyorg/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 runcomposer global require foo/foo
, followed later bycomposer 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, theglobal
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.
The text was updated successfully, but these errors were encountered: