Welcome! Please see the About page for a little more info on how this works.

+2 votes
in Clojure CLI by
retagged by

In tools.deps, when using git deps, the following declared dependencies:

{io.github.xadecimal/riddley {...}}

{com.github.xadecimal/riddley {...}}

{com.xadecimal/riddley {:git/url "https://github.com/xadecimal/riddley.git" ...}}

{com.xadecimal/riddley {:mvn/version ...}}

{garbage/whatever {:git/url "https://github.com/xadecimal/riddley.git" ...}}

will all resolve, but they will not conflict against one another, even though they are all the same lib.

As it stands, the consumer that declares the dependency can choose from all these equivalent declarations, but if it chooses differently than any of its transitive dependencies have chosen, a hidden conflict is created, and more than one version of the lib will be pulled into the classpath, giving non-deterministic behavior to what version of the code will actually be used at runtime.

This problem could be solved by letting the lib author choose the canonical lib group/name that users must use always when declaring a dependency on it.

This can be achieved by adding a new key to deps.edn, such as :lib which takes a fully qualified symbol which will be validated against the symbol declared in the :deps map of the consuming libs.

deps.edn of the library being depended upon:

{:lib com.xadecimal/riddley ;; <-- This new key is added to deps.edn, declaring the canonical lib name
 :paths ["src"]
 :deps {...}
 ...}

deps.edn of the libraries that declare a dependency on the above lib:

{:paths ["src"]
 :deps {com.xadecimal/riddley {...}}
 ...}

When tools.deps resolves the above, it will check if the pulled lib has :lib key declared in its deps.edn, if it does, it will assert that the symbol used here matches the declared :lib symbol, if it does not, it will error to the user, making this an illegal dependency declaration. In the above it is correct, but in the following it is wrong:

deps.edn of a library that badly declared an illegal dependency on the above lib:

{:paths ["src"]
 :deps {com.github.xadecimal/riddley {...}}
 ...}

This would error, because even if the library is found at github.com/xadecimal/riddley.git and thus the above resolves, the library at github.com/xadecimal/riddley.git declared that its canonical lib name was com.xadecimal/riddley and not com.github.xadecimal/riddley. Therefore, in this case the only valid git dependency declaration is:

{:paths ["src"]
 :deps {com.xadecimal/riddley {:git/url "https://github.com/xadecimal/riddley.git" ...}}
 ...}

This validation would follow a similar ideology to asserting that the git/tag matches the git/sha, by asserting that the lib name used matches what the lib expects to uniquely be identified by.

Doing this allows conflict resolution to work as expected, and avoids the possibility that transitive dependencies use a different name, causing hidden runtime version conflicts not detected and resolved by tools.deps.

1 Answer

0 votes
by

Don't think I want to add an attr to deps.edn re the lib name you "should" be using. We've generally tried to avoid adding project identifier info to the deps file itself.

Open to adding validation to detect "conflicting" dep libs (but this is a more general problem based on contents). I've filed this at https://clojure.atlassian.net/browse/TDEPS-229 for future work.

FYI, the lib that will be first on the classpath is deterministic - it will be the one at the highest "level" of your dep tree, and then by alpha sort in that level.

...