We have slowly been running into this more and more and as part of our solution
to the problem, we switched from Leiningen to Boot. There were many reasons for
the switch but easier management of dependencies was one aspect.
We created a centralized properties file with the dependencies we wanted pinned
across all our projects (this is just a small part of it):
mysql/mysql-connector-java=5.1.36
org.clojure/clojure=1.8.0
org.clojure/core.cache=0.6.4
org.clojure/core.memoize=0.5.8
Then our various `build.boot` files read this file and use it to patch up the
dependencies in each project:
(defn load-versions
"Read in pinned dependency versions."
[]
(into {} (doto (java.util.Properties.)
(.load (io/input-stream (str (ws-root)
"/clojure/version.properties"))))))
(def ^:private versions (delay (load-versions)))
We have switched to keeping dependencies (for each project) in an EDN file so
it’s separate from our actual build files and we read that in like this:
(defn update-deps
"Given a set of dependencies, automatically update ones that
we pin using external version properties file."
[deps]
(into [] (map (fn [[artifact version :as dep]]
(if-let [pinned (@versions (str artifact))]
[artifact pinned]
dep)) deps)))
(defn datamapper-deps
"Read dependencies from datamapper project."
[]
(-> (edn/read-string (slurp (str (ws-root) "/clojure/datamapper/deps.edn")))
update-deps))
And then we have tasks to set up the "context" for each project, for example:
(deftask datamapper
"Provide data mapper context."
[]
(merge-env! :source-paths #{"clojure/datamapper/src"}
:dependencies (datamapper-deps))
(environment))
Where datamapper depends on the environment project. So the dependencies are
read from the EDN file and updated to the pinned version in the properties
file. Then we just compose the context tasks as needed into other tasks that
invoke code based on them (including building JARs etc).
Inside each EDN file, we indicate the fake versions like this:
[[org.clojure/clojure "x.y.z"]
[org.clojure/core.cache "x.y.z"]
[org.clojure/core.memoize "x.y.z"]
[org.clojure/data.codec "x.y.z"]
[org.clojure/java.jdbc "x.y.z"]
[org.clojure/tools.nrepl "x.y.z"]
…
Sean Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
"If you're not annoying somebody, you're not really alive."
-- Margaret Atwood
From: Clojure Mailing List <[email protected]> on behalf of Chris Price
<[email protected]>
Reply-To: Clojure Mailing List <[email protected]>
Date: Sunday, January 24, 2016 at 1:39 PM
To: Clojure Mailing List <[email protected]>
Subject: lein: managing versions of common deps / soliciting assistance on PR
review
Hi,
As the number of Clojure projects at our company has increased, we've ended up
running into more and more frequent issues where lein's "pedantic" is alerting
us to conflicting versions of transitive dependencies. Up until now we've been
managing this by surgically updating the lists of dependencies / exclusions in
each project until everything matches up, but that's kind of like a giant game
of whack-a-mole and has left us vulnerable to situations where we're
unwittingly running a bunch of our CI jobs against a different version of some
of our dependencies than the versions that we end up including in our final
builds.
I'm curious how often this has been coming up for others, and whether or not
anyone has found a solution or workaround for it that they are really happy
with.
I've seen a couple of cool things that people have put out there, e.g.:
https://github.com/achin/lein-parent
https://github.com/walmartlabs/shared-deps
Both of these seem to be taking an approach somewhat similar to Maven's own
solution, which is the "parent pom" / project inheritance[1] approach (along
with the "managedDependencies" section of a pom file). Given that, and given
that lein's dependency management is already built on top of Maven, I've been
wondering if it would make sense to try to bring in support for parent projects
and managed dependencies as first-class constructs in leiningen.
E.g.:
(defproject my-parent-project "1.0.0"
:description "Parent project"
:managed-dependencies [[clj-time "0.10.0"]
[core.async "1.0"]])
Then you could have child projects foo and bar:
(defproject foo "1.0.0"
:parent-project [my-parent-project "1.0.0"]
:dependencies [[clj-time]
[some-other-dep "2.0.0"]])
(defproject bar "1.0.0"
:parent-project [my-parent-project "1.0.0"]
:dependencies [[core.async]
[yet-another-dep "3.0.0"]])
In this example, foo would automatically get the correct version of clj-time
from the parent, but would not drag in core.async at all. Likewise, bar would
get the correct version of core.async but would not drag in clj-time. When you
wanted to bump to a newer version of clj-time or core.async across all of your
projects, you'd just update the parent project.
I'd be really curious to hear whether there are other people out there who
would find this useful, or if we're just doing something wrong :)
If there is some level of interest in this I'd be happy to work on PRs for it;
I've already done a fair amount of exploration. In fact, I've already put
together one PR against cemerick/pomegranate to add support there for Maven's
"managedDependencies", which I think would be a pre-req for getting any of the
rest of this into leiningen:
https://github.com/cemerick/pomegranate/pull/73
If there are other folks out there who think this might be useful, I'd be
grateful for any feedback or review on the above PR.
Definitely still very interested to hear what other solutions people may have
come up with for this, though.
[1]
https://maven.apache.org/guides/introduction/introduction-to-the-pom.html#Project_Inheritance
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.