https://github.com/cemerick/pomegranate.git
git clone 'https://github.com/cemerick/pomegranate.git'
(ql:quickload :cemerick.pomegranate)
Pomegranate is a library that provides:
A sane Clojure API for Maven-resolver (originally called Aether).
A re-implementation of
add-classpath
(deprecated in Clojure core) that:
is a little more comprehensive than core's add-classpath
— it should work as
expected in more circumstances, and
optionally uses Maven-resolver to add a Maven artifact (and all of its transitive dependencies) to your Clojure runtime's classpath dynamically.
Insofar as most useful Clojure libraries have dependencies, any reasonable
implementation of the add-classpath
concept must seamlessly support resolving
those dependencies IMO.
Pomegranate is available in Maven central. Add it to your Leiningen
project.clj
:
[com.cemerick/pomegranate "1.1.0"]
or to your Maven project's pom.xml
:
<dependency>
<groupId>com.cemerick</groupId>
<artifactId>pomegranate</artifactId>
<version>1.1.0</version>
</dependency>
add-classpath
usageJust to set a stage: you're at the REPL, and you've got some useful data that you'd like to munge and analyze in various ways. Maybe it's something you've generated locally, maybe it's data on a production machine and you're logged in via nREPL. In any case, you'd like to work with the data, but realize that you don't have the libraries you need do what you want. Your choices at this point are:
pr
(assuming it's just Clojure data structures!),
and start up a new Clojure process with the appropriate libraries on the
classpath. This can really suck if the data is in a remote environment.add-claspath
, but the library
you want has 12 bajillion dependencies, and there's no way you're going to
hunt them down manually.Let's say we want to use Incanter (which
has roughly 40 dependencies — far too many for us to reasonably locate and add
via add-classpath
manually):
=> (require '(incanter core stats charts))
#<CompilerException java.io.FileNotFoundException:
Could not locate incanter/core__init.class or incanter/core.clj on classpath: (NO_SOURCE_FILE:0)>
Looks bleak. Assuming you've got Pomegranate on your classpath already, you can do this though:
=> (use '[cemerick.pomegranate :only (add-dependencies)])
nil
=> (add-dependencies :coordinates '[[incanter "1.9.2"]]
:repositories (merge cemerick.pomegranate.aether/maven-central
{"clojars" "https://clojars.org/repo"}))
;...add-dependencies returns full dependency graph...
=> (require '(incanter core stats charts))
nil
Now you can analyze and chart away, Incanter having been added to your runtime.
Note that add-dependencies
may crunch along for a while — it may need to
download dependencies, so you're waiting on the network. All resolved
dependencies are stored in the default local repository (~/.m2/repository
),
and if they are found there, then they are not downloaded.
The arguments to add-dependencies
look like Leiningen-style notation, and they
are.
Please note that there are a number of scenarios in which add-dependencies
will not work, or will not work as you'd expect. Many of these are due to the
nature of JVM classloaders (e.g. adding jars containing conflicting versions of
a particular dependency will rarely end well), which Pomegranate does not
currently attempt to hide. Thus, add-classpath
and add-dependencies
should
be considered escape hatches to be used when necessary, rather than a regular
part of your development workflow.
URLClassLoader
modifiabilityStarting with pomegranate 1.0.0
, java.net.URLClassLoader
s are not modifiable
by default. This is to accommodate new reflection policy starting with JDK 9
(which currently issues an ugly warning on reflective access to non-public
methods, but future releases will simply fail). If you are in a situation where
you are using pomegranate but do not have a clojure.lang.DynamicClassLoader
visible in your classloader hierarchy, you will need to explicitly enable the
java.net.URLClassLoader
support in
dynapath (upon which pomegranate relies
for such things).
Pomegranate is being used by Leiningen v2.x as its sole dependency resolution library. This has prompted rapid maturation of the scope and quality of Aether support. That said, specific API points remain subject to change as we find the right abstractions and conventions.
See the CHANGES.md
file at the top level of the repo.
Copyright © 2011-2017 Chas Emerick and all other contributors.
Licensed under the EPL. (See the file epl-v10.html.)