What are the workarounds when Composer dependencies conflict in versions? - composer-php

My projects depends on two packages, A and B, and they both depend on some-library, unfortunately in incompatible versions:
A depends on lib # 1.0
B depends on lib # 2.0
This is unresolvable by Composer because PHP can only load a single version of a class / interface at runtime.
What are my options? I am fine with "ugly" workarounds as long as they are automated. Doing fragile and manual work like forking A and upgrading its usage of some-library is something I'd like to avoid at all costs.

There are no workarounds. By design, Composer assumes that your project uses consistent dependencies and everything is maintained valid.
As mentioned in the comments, you can prefix the dependencies to isolate the part of the project that needs a particular library version. In this way, the prefixed code is consistent in Composer terms and you can continue developing with the latest versions.
These are a couple of prefixers that I can recommend:
humbug/php-scoper is a well-known tool that can prefix code based on Search & Replace steps (Finders and Patchers).
PHP-Prefixer is an automated online service to apply prefixes to Composer dependencies, based on composer.json definitions. You define the new namespace and prefix for your project.
Disclaimer: I'm the lead PHP-Prefixer developer.

Related

Sharing gradle dependencies: version catalog vs plugin

Gradle is working on new features for sharing dependency versions between projects that will provide central locations (settings.gradle, libs.versions.toml) for declaring common dependencies.
It's already possible (and easy) to share a dependencies block through a plugin, so what is the downside of the plugin approach to sharing dependencies, versus the new version catalogs and dependency bundles? What do these new features improve upon?
This is not a thorough answer. However, let me share what I think makes a difference. We need to keep in mind that Gradle is built around developer productivity and making builds as fast as possible.
Centralizing common dependency declaration makes sense to be supported out of the box. Currently, there is a good chance that when you look at different Gradle projects, each one of them may implement a different approach to this. Cédric Champeau iterates over some existing pattern in this blog. Having a standard solution makes it easier to get started as developer. Cédric further states
Long story short: the presence of a catalog makes discoverability and maintenance easier, but it doesn’t remove any of the flexibility that Gradle offers. We’re thinking about ways to enforce that all direct dependencies are declared via a catalog in the future.
Declaring dependencies in libs.versions.toml allows Gradle to skip build script compilation when dependency versions are changed. This is significantly faster than changing the same in a script plugin. As a side-effect of declaring dependencies in libs.versions.toml, we may see third-party tooling that update dependencies automatically in the future.

What are the benefits of having a vendor folder?

I can't really grasp the purpose of having a vendor folder. Based on what I learned, it seems the vendor folder is only beneficial if you're trying to make your repo compatible with golang versions earlier than 1.11. We are running golang 1.12.14.
When I brought this up to my coworker he said:
Please use vendor with modules - go doesn't have a global artifactory. this is, currently, the best option to make sure you have hermetic builds and your code doesn't break when somebody changes something in their repo.
I thought this is what Go modules does? I asked this question and a commenter is saying I shouldn't use vendor? Does it make sense to add `go mod vendor` to a pre-commit hook?
Go modules bring the guarantee that you will be able to build your packages deterministically by locking down the dependencies into a go.sum. That being said, the promise to deterministically build your project only stands if your dependencies are still accessible in the future. You don't know if this is going to be the case.
Vendoring on the other hand, with or without Go modules, brings stronger guarantees as it enables to commit the dependencies next to the code. Thus even if the remote repository is no longer accessible (deleted, renamed, etc), you will still be able to build your project.
Another alternative is to use Go modules along with a proxy. You can find more information in the official documentation. You can also look at some OSS implementations like gomods/athens or goproxy/goproxy. If you don't feel like setting up and maintaining your own proxy, some commercial offers are available on the market.
So should you go mod vendor each time you commit? Well it's ultimately up to you dependending on the kind of guarantees you want. But yes leveraging a proxy or vendoring your dependencies help getting closer to reproducable builds.
Note: with Go 1.17, go mod vendor (from 1.17 Go commands) might be easier to use:
vendor contents
If the main module specifies go 1.17 or higher, go mod vendor now annotates vendor/modules.txt with the go version indicated by each vendored module in its own go.mod file.
The annotated version is used when building the module's packages from vendored source code.
If the main module specifies go 1.17 or higher, go mod vendor now omits go.mod and go.sum files for vendored dependencies, which can otherwise interfere with the ability of the go command to identify the correct module root when invoked within the vendor tree.
Vendor Folder is a great way to organize and manage third-party dependencies in your project. It is especially useful when your code relies on external libraries or frameworks.
Benefits of having a Vendor Folder:
It helps to reduce dependencies conflicts.
It allows you to keep a separate version of each library / framework installed in your project.
It helps to keep the project structure clean and organized.
It makes it easy to update, install, and remove any dependencies with minimal effort.
It makes it easier to switch between different versions of a library or framework.

What is the difference between deps and dev-deps in Poetry?

In the pyproject.toml configuration file of Poetry you can specify both dependencies and dev-dependencies, but the documentation does not state clearly what the difference is.
I guess from the name the dev-dependencies will not be installed by a release build, but I didn't notice any difference. How do you use these fields correctly, for example exclude the dev-dependencies in a build?
Your assumption is right. The best use case for dev-dependencies is when you creating a library with optional dependencies. For instance, you are developing ORM which should work with MySQL, PostgreSQL, etc. You have to test that your code is working with all of these RDBMS. You put it into dev-dependencies. But for one, who installs your library, these dependencies are optional and they wouldn't be installed automatically.
Commonly, all libraries that are used for testing or building your application are presented at dev-dependencies.
How do you use these fields correctly, for example exclude the dev-dependencies in a build?
poetry install has a no-dev flag for exactly that scenario.

Make sure bundles use same dependencies versions

I am looking for a way to ensure that all the features I deploy in Karaf require dependencies that are of the same version. The project is composed of more than 40 bundles which makes it difficult to verify manually.
I am thinking of developping a Maven plug-in that would make the check, but before I would like to be sure that such a solution do not exist yet.
If you want to be sure you use the same versions then create a parent project and define versions of dependencies only there. So you can be sure all your modules have the same dependencies. Of course this only makes sense if all these modules are very closely related (e.g. belong to the same application / release unit).
Why would you even want to do this? Each bundle should depend on the versions of the package it needs, and that dependency should be a range. So if you compile against and API package version 1.0.0, and you are a consumer of that API, then you should import with the range [1.0.0, 2.0.0). Refer to the OSGi Core Release 5 specification, section 3.7.3 ("Semantic Versioning") for details.
At runtime the OSGi Framework will ensure that your bundle is wired to a package version that is within its permitted range. Obviously if you have non-overlapping version ranges from different importers then the Framework will not be able to satisfy them with a single exporter.

How to set the version of my project?

How do I set the version and stability of my composer project?
I assumed this would be done in the composer.json file, but none of the popular frameworks seem to have anything in there indicating the version of the current project, just their dependencies. How do I set it?
The documentation is buried under a section called "tags".
Basically, the preferred method of adding versions is by creating a VCS tag that "looks" like a version. Composer will read these tags and determine the version based on that.

Resources