2016-06-27 18:41:59 +00:00
|
|
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
|
|
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
|
|
|
|
|
|
|
# Managed Dependencies With Leiningen
|
|
|
|
|
|
|
|
Maven (and now Leiningen) provides a capability called "Dependency Management".
|
|
|
|
The idea is to provide a way to specify a version number for common library
|
|
|
|
dependencies in a single location, and re-use those version numbers from other
|
|
|
|
discrete maven/lein projects. This makes it easy to, e.g., update your `clj-time`
|
|
|
|
dependency across a large number of projects without having to be mindful
|
|
|
|
of every common dependency version across all of your libraries.
|
|
|
|
|
|
|
|
When using `:pedantic? :abort` in your projects, to ensure that you are producing
|
2017-01-22 21:19:25 +00:00
|
|
|
a consistent and predictable build, it can be very cumbersome to play the
|
2017-01-11 19:06:57 +00:00
|
|
|
"dependency version whack-a-mole" game that arises whenever an upstream library
|
|
|
|
bumps a version of one of its dependencies. `:managed-dependencies` can help
|
|
|
|
alleviate this issue by allowing you to keep the dependency version numbers
|
|
|
|
centralized.
|
2016-06-27 18:41:59 +00:00
|
|
|
|
|
|
|
## `:managed-dependencies`
|
|
|
|
|
|
|
|
The `:managed-dependencies` section of your `project.clj` file is just like the
|
|
|
|
regular `:dependencies` section, with two exceptions:
|
|
|
|
|
|
|
|
1. It does not actually introduce any dependencies to your project. It only says,
|
|
|
|
"hey leiningen, if you encounter one of these dependencies later, here are the
|
2016-06-30 16:41:27 +00:00
|
|
|
versions that you should fall back to if the version numbers aren't explicitly
|
|
|
|
specified."
|
2016-06-27 18:41:59 +00:00
|
|
|
2. It allows the version number to be omitted from the `:dependencies` section,
|
|
|
|
for any artifact that you've listed in your `:managed-dependencies` section.
|
|
|
|
|
|
|
|
Here's an example:
|
|
|
|
|
2016-06-30 16:41:27 +00:00
|
|
|
```clj
|
2016-06-27 18:41:59 +00:00
|
|
|
(defproject superfun/happyslide "1.0.0-SNAPSHOT"
|
|
|
|
:description "A Clojure project with managed dependencies"
|
|
|
|
:min-lein-version "2.7.0"
|
|
|
|
:managed-dependencies [[clj-time "0.12.0"]
|
|
|
|
[me.raynes/fs "1.4.6"]
|
|
|
|
[ring/ring-codec "1.0.1"]]
|
|
|
|
:dependencies [[clj-time]
|
|
|
|
[me.raynes/fs]])
|
|
|
|
```
|
|
|
|
|
|
|
|
In the example above, the final, resolved project will end up using the specified
|
|
|
|
versions of `clj-time` and `me.raynes/fs`. It will not have an actual dependency
|
|
|
|
on `ring/ring-codec` at all, since that is not mentioned in the "real" `:dependencies`
|
|
|
|
section.
|
|
|
|
|
|
|
|
This feature is not all that useful on its own, because in the example above,
|
|
|
|
we're specifying the `:managed-dependencies` and `:dependencies` sections right
|
|
|
|
alongside one another, and you could just as easily include the version numbers
|
|
|
|
directly in the `:dependencies` section. The feature becomes more powerful
|
|
|
|
when your build workflow includes some other way of sharing the `:managed-dependencies`
|
|
|
|
section across multiple projects.
|
|
|
|
|
2016-09-01 17:48:11 +00:00
|
|
|
## A note on modifiers (`:exclusions`, `:classifier`, etc.)
|
|
|
|
|
2016-09-16 22:07:40 +00:00
|
|
|
The managed dependencies support in leiningen *does* work with modifiers such as
|
|
|
|
`:exclusions` and `:classifier`. There are two legal syntaxes; you can explicitly
|
|
|
|
specify a `nil` for the version string, or you can simply omit the version string:
|
|
|
|
|
|
|
|
```clj
|
|
|
|
(defproject superfun/happyslide "1.0.0-SNAPSHOT"
|
|
|
|
:description "A Clojure project with managed dependencies"
|
|
|
|
:min-lein-version "2.7.0"
|
|
|
|
:managed-dependencies [[clj-time "0.12.0"]]
|
|
|
|
:dependencies [[clj-time :exclusions [foo]]])
|
|
|
|
```
|
|
|
|
|
|
|
|
or
|
2016-09-01 17:48:11 +00:00
|
|
|
|
|
|
|
```clj
|
|
|
|
(defproject superfun/happyslide "1.0.0-SNAPSHOT"
|
|
|
|
:description "A Clojure project with managed dependencies"
|
|
|
|
:min-lein-version "2.7.0"
|
|
|
|
:managed-dependencies [[clj-time "0.12.0"]]
|
|
|
|
:dependencies [[clj-time nil :exclusions [foo]]])
|
|
|
|
```
|
|
|
|
|
2016-09-16 22:07:40 +00:00
|
|
|
Note that `:classifier` is actually a part of the maven coordinates for an
|
|
|
|
artifact, so for `:classifier` artifacts you will need to specify the `:classifier`
|
|
|
|
value in both the `:managed-dependencies` and the normal `:dependencies` section:
|
|
|
|
|
|
|
|
|
|
|
|
```clj
|
|
|
|
(defproject superfun/happyslide "1.0.0-SNAPSHOT"
|
|
|
|
:description "A Clojure project with managed dependencies"
|
|
|
|
:min-lein-version "2.7.0"
|
|
|
|
:managed-dependencies [[commons-math "1.2" :classifier "sources"]]
|
|
|
|
:dependencies [[commons-math :classifier "sources"]])
|
|
|
|
```
|
2016-09-01 17:48:11 +00:00
|
|
|
|
2016-06-27 18:41:59 +00:00
|
|
|
## Lein "parent" projects
|
|
|
|
|
|
|
|
One way of leveraging `:managed-dependencies` across multiple projects is to use
|
|
|
|
the [`lein-parent` plugin](https://github.com/achin/lein-parent). This plugin
|
|
|
|
will allow you to define a single "parent" project that is inherited by multiple
|
|
|
|
"child" projects; e.g.:
|
|
|
|
|
2016-06-30 16:41:27 +00:00
|
|
|
```clj
|
2016-06-27 18:41:59 +00:00
|
|
|
(defproject superfun/myparent "1.0.0"
|
|
|
|
:managed-dependencies [[clj-time "0.12.0"]
|
|
|
|
[me.raynes/fs "1.4.6"]
|
|
|
|
[ring/ring-codec "1.0.1"]])
|
|
|
|
|
|
|
|
(defproject superfun/kid-a "1.0.0-SNAPSHOT"
|
|
|
|
:parent-project [:coords [superfun/myparent "1.0.0"]
|
2016-08-30 21:13:32 +00:00
|
|
|
:inherit [:managed-dependencies]]
|
2016-06-27 18:41:59 +00:00
|
|
|
:dependencies [[clj-time]
|
|
|
|
[me.raynes/fs]])
|
|
|
|
|
|
|
|
(defproject superfun/kid-b "1.0.0-SNAPSHOT"
|
|
|
|
:parent-project [:coords [superfun/myparent "1.0.0"]
|
2016-08-30 21:13:32 +00:00
|
|
|
:inherit [:managed-dependencies]]
|
2016-06-27 18:41:59 +00:00
|
|
|
:dependencies [[clj-time]
|
|
|
|
[ring/ring-codec]])
|
|
|
|
```
|
|
|
|
|
|
|
|
In this example, we've consolidated the task of managing common version dependencies
|
|
|
|
in the parent project, and defined two child projects that will inherit those
|
|
|
|
dependency versions from the parent without needing to specify them explicitly.
|
|
|
|
|
|
|
|
This makes it easier to ensure that all of your projects are using the same versions
|
|
|
|
of your common dependencies, which can help make sure that your uberjar builds are
|
|
|
|
more predictable and repeatable.
|
|
|
|
|
|
|
|
## Other ways to share 'managed-dependencies'
|
|
|
|
|
|
|
|
Since the `defproject` form is a macro, it would be possible to write other plugins
|
|
|
|
that generated the value for a `:managed-dependencies` section dynamically. That
|
|
|
|
could provide other useful ways to take advantage of the `:managed-dependencies`
|
|
|
|
functionality without needing to explicitly populate that section in all of your
|
|
|
|
`project.clj` files.
|
|
|
|
|
|
|
|
## Future integration
|
|
|
|
|
|
|
|
It is likely that the functionality provided by the `lein-parent` plugin may integrated
|
|
|
|
into the leiningen core in a future release; for now we have added only the `:managed-dependencies`
|
|
|
|
functionality because it is necessary in order for the plugin to leverage it. We
|
|
|
|
will be experimenting with different ideas for implementation / API in plugins and
|
|
|
|
making sure that we find an API that works well before submitting for inclusion
|
|
|
|
into core leiningen.
|