This is the scenario.
You have package A and package B in your composer.json (your app depends on this 2 packages).
Both package A and B depend on package C, but on different versions. Say A depend on C v2.1, and B depends on C v2.2.
And you get version conflicts.
Both A, B and C are third party packages.
How to resolve this?
This is a hack but will probably let you move forward.
You could overwrite repositories for "A", "B" and "C" packages and make that "A" and "B" rely on the same version of "C" (actually, might be that it's enough to overwrite repositories for "A" and "B" only).
This should work as long as both "A" and "B" can work with the latest version of "C" (so probably a maintainer didn't update the package version). If it's the case I'd also consider sending a pull request to the project which has an older version of a dependency.
We are discussing it in this mailing list : http://news.php.net/php.internals/72594
"No-conflict" technique must be implemented in PHP , it's not a composer fault
Related
Imagine you have a project which requires two modules A and B. I will call the project module P. Let's say that P requires A v1.0.0, B v1.1.0 and that A requires B v1.0.0. Furthermore B did not adhered semantic versioning rules thus the version change from v1.0.0 -> v1.1.0 introduced a breaking API change. So
P only builds with v1.1.0 and A only builds with v1.0.0.
Dependency graph:
P -> A (v1.0.0) -> B(v1.0.0)
P -> B (v1.1.0)
Is there any way to build this project with different versions. I heared about vendoring but I'm not sure if this would cause the dependency to use a different B module version.
And if it could provide a solution for the conflicting package versions, does the go tool recognize modules using vendoring if the dependencies do not include a vendor folder (some people say, you should not upload the vendor folder) in their git repository (In this case module A does not ship with a vendor folder, but the developer called go mod vendor locally), does the go get command respect vendor folders of dependencies (or can it detect that the module used vendoring without an upstream vendor folder)?
This seems like a conflict the module system cannot resolve. Since Go uses semantic versioning it will try to get B v1.1.0 to resolve both dependencies and then the build will break if A cannot work with B 1.1.0.
The best way to resolve it is to fix B by not breaking the API in a non-major version.
Lacking that, you could fork B into a separate module (with a different module name from the original B) and use an old version in A. Create BFORK=Bv1.0.0, and then you'll have:
P -> B (v1.0.0)
A -> BFORK vX.X.X
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
In one of my recent interviews, I was asked about how does a package manager tool like npm or pip might work internally in terms of figuring out which dependencies to install first.
For instance, say you want to install a package A which depends upon package B, which in turn depends on package C. In such a case, the package C should be installed first followed by B and then A.
The dependency trail can get a lot more complicated which I might believe can be represented in the form of a graph. Now the question is to figure out if there exists a cyclic dependency amongst the packages and if not, then to print the packages in the order in which they should be installed.
I couldn't come up with a correct/optimal solution in time, but maybe someone from here can help?
Thanks!
The dependency between packages can be modeled as a Directed Acyclic Graph.
A dependency graph is invalid if it contains a cycle, for which you can refer to the following algorithm for detecting a cycle in a directed graph: https://www.geeksforgeeks.org/detect-cycle-in-a-graph/
If there's no cycle in the graph, then you can perform a topological sort to obtain the order in which the dependencies should be installed: https://www.geeksforgeeks.org/topological-sorting/
Hope this answers your question. Cheers!
Please follow this link of npm algo for more clarification
Dependency Resolution
I am taking the exact example provided in the npm documentation.
Note: From the v3 the dependency resolution algorithm is changed so this example applicable for v3 and above npm versions.
Lets consider the following example :
Module-A, depends on Module B v1.0.
Module-C, depends on Module B v2.0.
Note the sequence of modules mentioned because it plays a significant role in the dependency resolution.
So first is the module A in sequence and it depends on the module B v1.0, npm will install both module A and its dependency, module B, inside the /node_modules directory, flat.
Next in the sequence is module C which depends on again module B but with a different version. npm handles this by nesting the new, different, module B version dependency under the module that requires it
Now what happens if we install another module that depends on Module B v1.0? or Module B v2.0?
So lets say :
Module-D, depends on Module B v2.0.
Module-E, depends on Module B v1.0.
Because B v1.0 is already a top-level dependency, we cannot install B v2.0 as a top level dependency. Therefore Module B v2.0 is installed as a nested dependency of Module D, even though we already have a copy installed, nested beneath Module C. Module B v1.0 is already a top-level dependency, we do not need to duplicate and nest it. We simply install Module E and it shares Module B v1.0 with Module A.
Now the interesting part, what happens if we update Module A to v2.0, which depends on Module B v2.0, not Module B v1.0 ?
The key is to remember that install order matters.
Even though Module A was installed first (as v1.0) via our package.json, using npm install command means that Module A v2.0 is the last package installed.
As a result, npm does the following things when we install module A v2.0
It removes Module A v1.0.
It installs Modules A v2.0.
It leaves Module Bv1.0 because Module E v1.0 still depends on it.
It installs Module Bv2.0 as a nested dependency under Module A v2.0, since Module B v1.0 is already occupying the top level in the directory hierarchy.
Finally, let’s also update Module E to v2.0, which also depends on Module B v2.0 instead of Module B v1.0, just like the Module A update.
npm performs the following things:
It removes Module E v1.0.
It installs Module E v2.0.
It removes Module B v1.0 because nothing depends on it anymore.
It installs Module B v2.0 in the top level of the directory because there is no other version of Module B there.
Now, this is clearly not ideal. We have Module B v2.0 in nearly every directory. To get rid of duplication, we can run:
npm dedupe
This command resolves all of the packages dependencies on Module B v2.0 by redirecting them to the top level copy of Module B v2.0 and removes all the nested copies.
Conclusion
So the key take away from this example is that installation order matters and that can be ensured only by using npm command while adding or updating any package in the project. There may be possibility the generated dependency tree by npm would be different on different local development machine but it wont affect the behavior of your application because Even though the trees are different, both sufficiently install and point all your dependencies at all their dependencies, and so on, down the tree. You still have everything you need, it just happens to be in a different configuration.
if you want your node_modules directory to be the same than use npm install command, when used exclusively to install packages from a package.json, will always produce the same tree. This is because install order from a package.json is always alphabetical. Same install order means that you will get the same tree.
You can reliably get the same dependency tree by removing your node_modules directory and running npm install whenever you make a change to your package.json.
In my project I have module M1 it use library A. This library have dependency to library B.
And in another module M2 I want to use library B.
And of course I have "root" module which depend on all my modules so versions of library B should be the same across all projects.
So I added B to dependency of my M2 module but don't know how to specify it version because I need exactly same version as library A use.
If I specify current version of library B then when I will upgrade library A to new version I will forget to update version of B in my module.
Also I don't want to put A as dependency of M2 because I need only limited part of it's functionality.
What is best practices for my case?
The maven enforce plugin can break the build if the versions diverge so that yo do not forget to update: see https://maven.apache.org/enforcer/enforcer-rules/dependencyConvergence.html
There are several options some of them you exclude explicitely. Let me mention them for the sake of completeness anyway:
Include B as a dependency in M2.
Advantage: Cleanest solution with respect to adding only those functionality to M2 that's actually needed.
Disadvantage: Version of B in M2 has to be kept in sync with versin of B in A manually.
Include A as a dependency in M2.
Advantage: Central <DependencyManagement> can be used in your parent POM. Hence, Versions of B will always be the same in all sub-projects.
Disadvantage: Functionality of A not needed in M2 is added to M2.
Include M1 as a dependency in M2.
Advantage: M2 always uses the same version of B as A without having to deal with B as a dependency at all.
Disadvantage: Functionality of M1 and of A not needed in M2 is added to M2.
Use <dependency>/.../<exclusion> to exclude B from A in M1.
Advantage: Central <DependencyManagement> can be used in your parent POM. Hence, Versions of B will always be the same in all sub-projects.
Disadvantage: Version of B has to be kept in sync with version of B in A manually.
[Input is welcome in case there's anything else I haven't thought of.]
Try Maven Enforcer Plugin's Dependency Convergence mentioned by Assen Kolov in his answer. If it works for a mixture of direct and transitive dependencies, like in your case, as well, I'd use it in conjunction with 1.
I'm not quite sure of the best way to handle the following situation in my Maven project...
I have two direct dependencies A and B. Both depend on different versions of C. Dependency A is compatible with both versions of C, but dependency B is only compatible with it's declared version of C. I'd like to simply use whatever version of C that B declares.
I realize that I can exclude the dependency of C in dependency A, but then if I ever removed dependency B or if C was removed as a dependency of B...A would not work anymore.
I also realize that I can declare B's current version of C in my dependency management section, but then I would not seamlessly get the change if B ever changed it's version of C.
What is the prescribed way to handle this sort of situation?
The best way as recommended, although, slightly indirectly, by the maven docs is to use the dependency management feature. Quoting the doc,
A second, and very important use of the dependency management section
is to control the versions of artifacts used in transitive
dependencies.
I can understand that you are forced to update the version of C on your target project, say T, every time B uses a new version of C, but you also have to look at this from the T's POV - the target project T, ought to know and be able to control all the versions of the transitive dependencies it has.
I am very new to OSGi.
I am developing a plugin A (osgi bundle), suppose A which depends on libraries, suppose B-1.0 and C-1.0. Now If the library C-1.0 depends on library B-2.0 (Note: the different version of library B). So my plugin has two different versions of the library B in its classpath. Now, How can I handle this situation ?
As I am studying from last 4-5 days about OSGi that it creates a classloader for each plugin in the JIRA application, so that dependency version mismatch do not occur between plugins. But What would a developer do If a plugin itself needs two different versions of a library jar ?
Can I create two different classloaders in a single osgi bundle through OSGi, say one for package X and another one for package Y ?
Please help me in any of the above scenarios or point me to the right direction.
Thanks in advance.
Remember that bundles do not depend on other bundles!!
Bundles import packages that are exported by other bundles. (unless you have used Require-Bundle, but you should not). So to rephrase the scenario from your example:
Bundle A imports package org.foo. Bundle C exports package org.foo, and OSGi wires the import to the export. So far so good.
Bundle C also imports package org.bar. Bundle B 1.0 exports package org.bar. Therefore OSGi wires these together and everything is still fine.
Now... bundle A also imports package org.wibble. Bundle B 2.0 exports package org.wibble. This is fine as well! Bundles B 1.0 and B 2.0 are simply different bundles as far as OSGi is concerned, they can both be installed at the same time.
So when you look at the dependencies the way they actually work, you find that it's perfectly possible for A to import code that comes from two different versions of B. However there is a limitation. Consider the following:
Bundle D imports packages org.foo and org.bar v1.0 (yes, packages are versioned).
Bundle E exports package org.foo, which satisfies the import in D. Bundle E also imports package org.bar v2.0.
Some other bundles (say F v1 and F v2) export the 2 versions of the org.bar packages.
Actually this scenario can still work. D can import version 1.0 of package org.bar from somewhere, and E can import version 2.0 of package org.bar from somewhere else, at the same time as D is importing package org.foo from E. I personally find this pretty incredible! But it does not work if org.foo "uses" org.bar, where "uses" means that some types in org.bar are visible in the API of org.foo. In this case, bundle D would be exposed to 2 different copies org.bar, which is not allowed, so OSGi will prevent bundle D from running by not allowing it to enter RESOLVED or ACTIVE states.
In osgi bundle or plugin you'll have meta-inf flie which will define which classes you import if you pass extra agrument being the version=2.0 then it will use the class from B-2.0 if you don't specify anything then it'll resolve to one that is loaded by classloader first.
i.e.
import-package(C 1.0):
b.some.package; version="2.0" or b.some.package; version="[2.0,4.0)"
import-package(A 1.0):
b.some.package; version="1.0" or b.some.package; version="1.0"
Hope this helps
Anup
Since each OSGi bundle has its own classloader, there will be 4 bundles in the runtime, and also 4 classloaders (A, B-1.0, B-2.0, C-1.0).
You may have two copies of the same class included in B (one from 1.0 and another from 2.0). If you run this, you may simply run into a ClassCastException in the A code because two versions of B classes are not the same.
OSGi provides a "uses" clause to detect this type of situations early. For example, C may have a uses clauses like the following:
Export-Package: c.some.package;uses="b.some.package";version="1.0"
Import-Package: b.some.package;version="2.0"
In this case, you will have an earlier failure (while resolving A), known as a uses conflict, because C places a constraint for its consumer on an acceptable version of B.
Conceptually, the only way to fix this problem is to have consumers of B (A and C in this case) agree on the version of B.