Display loaded dependencies in leiningen REPL - clojure

I'm running into problems because the library I have appears to conflict with the published documentation. I had a few problems with getting the right version of things installed before, and I'm wondering if this is the cause.
Is there any way to print out which jars were loaded in the repl so I can check?

You can also use query lein for
the classpath with lein classpath
a dependency tree printout with lein deps :tree

This might also help:
lein deps :tree - shows a tree of dependencies that get pulled in
[library "version" :exclusions [some-other-lib "version"]] - exclude the some-other-lib that gets pulled in by some library.
You can then manually pull in the right version of some-other-lib by defining your own dependency vector.

(System/getProperty "java.class.path")

There are several options:
using java interrop: (System/getProperty "java.class.path"), (println (seq (.getURLs (java.lang.ClassLoader/getSystemClassLoader))))
clojure/java.classpath contains useful functions: like system-classpath
lein: lein classpath and lein deps :tree
boot: boot show -p, as well as useful function in boot environnement. Maybe have a look at martinklepsch/boot-deps.
For boot, I also wrote nha/boot-deps that helps managing dependency conflicts.

Related

Could not locate clojure/data/json: How do I get my REPL to see this (and similar) dependencies

I am using lein repl without a project so there is no project.clj.
I am running Leiningen 2.8.1 on Java 1.8.0_191 OpenJDK 64-Bit Server VM.
When I require a Clojure dependency that I assume should just work - like clojure.data.json - I notice that it is not in my .m2 directory. Is that why I am getting a FileNotFoundException Could not locate clojure/data/json__init.class or clojure/data/js
on.clj on classpath? I can't find my other Clojure dependencies there either so I don't know where they reside and if this dependancy should be in .m2 or not.
I understand the error message but without knowing its location or even knowing how to properly add it to the CLASSPATH for the REPL to see it, I remain stuck.
Is this a dependency that I still need to install? If so, how do I install it without going through a project?
I don't understand the JVM as I am new to it, so add a little extra information in your answer.
I have looked at this, this, this, this and this. I don't know if I am overlooking anything so your help will really be appreciated.
I am using lein run without a project so there is no project.clj.
If you're using Leiningen, this'll be much easier if you create a project.clj file that declares your dependencies. Leiningen will read project.clj and handle fetching any missing dependencies to your local Maven repository, and add them to your classpath when you start your REPL/application. (lein run doesn't work for me in a directory without a project.clj; I get an error: No :main namespace specified in project.clj.. Did you mean lein repl?)
When I require a Clojure dependency that I assume should just work - like clojure.data.json - I notice that it is not in my .m2 directory.
clojure.data.json doesn't ship with Clojure — it's a separate dependency that must be fetched and added to your classpath in order to use it. The classpath tells the JVM where to look when it loads class files. Leiningen will do both of these things for you if you declare the dependency in project.clj:
:dependencies [[org.clojure/clojure "1.10.0"]
[org.clojure/data.json "0.2.6"]]
You can also use the lein deps command if you only want to fetch dependencies.
You can create a new/blank Leiningen project with lein new project_name_goes_here. It will have a project.clj with a few boilerplate entries and a :dependencies key where you can declare dependencies.
I understand the error message but without knowing its location or even knowing how to properly add it to the CLASSPATH for the REPL to see it, I remain stuck. Is this a dependency that I still need to install? If so, how do I install it without going through a project?
You could manually download it from the internet, then manually add its path to your classpath, but if you're already using Leiningen it's much easier to add a line to a project.clj file and have Leiningen handle this for you.
If using a project.clj file w/Leiningen isn't an option, there are other ways to use Clojure and resolve dependencies/build a classpath at runtime. Boot accommodates this workflow, you can use Leiningen like this with a little added effort, as well as the newer tools.deps tooling. There are examples of each in this ClojureVerse thread, but note that some of these approaches are doing essentially the same thing as declaring the dependency in a file — instead declaring them as CLI arguments.
For example, using Clojure CLI tooling:
$ clj -Sdeps "{:deps {org.clojure/data.json {:mvn/version \"0.2.6\"}}}"
Clojure 1.9.0
user=> (require '[clojure.data.json :as json])
nil
user=> (json/write-str {:foo "bar"})
"{\"foo\":\"bar\"}"
user=> (System/getProperty "java.class.path")
"src:
/Users/me/.m2/repository/org/clojure/clojure/1.9.0/clojure-1.9.0.jar:
/Users/me/.m2/repository/org/clojure/data.json/0.2.6/data.json-0.2.6.jar:
/Users/me/.m2/repository/org/clojure/spec.alpha/0.1.143/spec.alpha-0.1.143.jar:
/Users/me/.m2/repository/org/clojure/core.specs.alpha/0.1.24/core.specs.alpha-0.1.24.jar"
You could create a deps.edn file containing {:deps {org.clojure/data.json {:mvn/version \"0.2.6\"}}} in the same directory, and clj would read that, resolve the dependencies if necessary, and build the classpath accordingly.
This is a great opportunity to use lein try. Once you add it to your ~/.lein/profiles.clj, you'd simply run: lein try org.clojure/data.json and you'll be greeted with a running REPL with that dependency just a require away.

How does this code end end up pulling all dependencies for clojure boot?

If you want to pull all dependencies for a boot Clojure project, it turns out you can add either of the following task to your build.boot file.
(deftask deps [])
or
(deftask deps [] (repl :server true))
The later also pulls the repl dependencies as mentioned here.
I cannot figure out why this works though.
Why does creating empty body task cause the task to pull all dependencies? How is it that (deftask z [] (comp (a) (b) (c)) will only pull the dependencies for a b c, but (deftask z []) will somehow pull all the dependencies for task defined in build.boot? Is it a magic sort of thing? If so, why not just include deps as a default boot task?
You've already linked the answer.
Repl Depencencies
The repl task is different from most other tasks because the nREPL
server can't be run in a pod (because you want to have a REPL in the
project context, not a fresh pod context). So the repl task calls
set-env! itself to add its nREPL dependencies at runtime when it is
actually used, and the project has no nREPL dependencies when the repl
task isn't used.
This means that the method described above will not fetch dependencies
needed to start the REPL. This could be an issue when building Docker
images, for example. The solution is to do something like this:
(deftask deps [] (repl :server true))
If you explicitly tell boot that you want to use nREPL it downloads all the required dependencies. The linked section also describes how this is done.
So the repl task calls set-env! itself to add its nREPL dependencies at runtime when it is actually used,
And that happens independent from your dependencies because your application may not have any additional dependencies.

Dependencies in profiles.clj aren't loaded in lein repl

.lein/profiles.clj has dependencies as,
{:user {}
:repl {:dependencies [[org.clojure/clojure "1.4.0"]
[ring/ring "1.1.6"]]
}}
in repl
(require 'ring.adapter.jetty)
throws,
java.io.FileNotFoundException: Could not locate ring/adapter/jetty__init.class or ring/adapter/jetty.clj on classpath: (NO_SOURCE_FILE:0)
This means, ring dependency is not loaded in repl shell. Any mistakes?
Firstly, I would recommend reading https://github.com/technomancy/leiningen/blob/stable/doc/PROFILES.md as I'm not sure you are using profiles correctly. In particular, at the end it shows a way of debugging your profiles, which will show you what is going on.
Secondly, I'm not sure about "there is no project - I am running it from bash shell". If your loading jetty and using ring, you will also need code which sets handlers, routes and probably middleware. this means code files, which means a project tree. Create a basic project with lein new and run from the root of that project.
However, if you really do need to do it as you say, I would suggest you just do
{:user {:dependencies [[....]]}} as your profiles.clj as I suspect that what is happening is that lein is not loading your :repl profile. You could also try running lein with the explicit profile i.e. lein with-profile +repl repl

Any way to add dependency to lein project without REPL restart?

What I do now is open project.clj, add dependency there, run lein deps restart repl, then use, require and so on.
The thing is that I don't really like to restart repl because the startup time is slow and I have to reload my files again.
So is there a better way to add dependency to lein project? without restarting the repl?
You can use Alembic, a dynamic classpath loader and dependencies resolver. The good thing is that it doesn't load all pomegranate dependencies.
Add the following to your .lein/profiles.clj:
{:user
{:dependencies [[alembic "0.3.2"]]}}
Then in your Repl just load the classpaths you need, they will be pulled from the repositories by leinif need:
(require 'alembic.still)
(alembic.still/distill '[enlive "1.1.5"])
(require 'net.cgrand.enlive-html) should now work.
for quick testing you can use pomegranate to add dependencies on the fly
=> (use '[cemerick.pomegranate :only (add-dependencies)])
nil
=> (add-dependencies :coordinates '[[incanter "1.2.3"]])
for actually adding a dependency I ususally hit
Alt-x nrepl-restart
ctrl-cctrl-k to reload the file,
ctrl-calt-n to get back to the namespace i in the buffer
The whole process takes the jvm startup time (which i agree is a touch painful) plus five seconds. It helps to keep your project in a state where loading a file does all the require initialization.

upgrading lein project from clojure 1.2.1 to 1.3.0-beta1

I have a leiningen project that uses clojure 1.2.1. I would like to add a dependency to a package that requires clojure 1.3.0-beta1. So I decided to upgrade my project to the newer version.
To be honest I was not sure what that involved but I did the following..
In my project.clj I changed my dependency from
[org.clojure/clojure "1.2.1] to [org.clojure/clojure "1.3.0"]
I use swank so I changed my swank clojure dependency to [swank-clojure "1.3.2"].
I then ran
lein deps
Lastly I manually edited my /usr/bin/lein file to change the CLOJURE_JAR variable to point to the newer clojure jar.
When I start swank with 'lein swank'. It starts fine and I now get the following warning messages
like so..
Warning: default-javac-options not declared dynamic and thus is not dynamically rebindable, >but its name suggests otherwise. Please either indicate ^:dynamic default-javac-options or >change the name.
Which I think has to do with clojure 1.3.0.
I then fire up Aquamacs and run slime-connect. The REPL starts fine but when call clojure-version
if get "1.2.1".
; SLIME 20100404
user> (clojure-version)
"1.2.1"
Is there something else I need to do?
I think, that you need to add :exclusions list to swank-clojure specification, something like:
:dev-dependencies [[swank-clojure "1.3.2"
:exclusions [org.clojure/clojure]]]
although, I just checked my installation, and clojure 1.3 worked out of box. I think, that you just forgot to call lein clean before lein deps...