How do I start an nREPL from the clj command?
I can't run my project using Lein or Boot because I have an unbalanced paren somewhere, and the reader complains `java.lang.RuntimeException: read-cond starting on line 13 requires an even number of forms.
Things are easier now than they were when the question was posted:
$ clj -Sdeps '{:deps {nrepl/nrepl {:mvn/version "0.5.3"}}}' -m nrepl.cmdline
More details here.
Wrote a gist on how to do this:
clj -Sdeps '{:deps {org.clojure/tools.nrepl {:mvn/version "0.2.12"}}}'
Clojure 1.9.0
user=> (use '[clojure.tools.nrepl.server :only (start-server stop-server)])
nil
user=> (defonce server (start-server :port 7888))
#'user/server
Now you can connect to port 7888 using your remote REPL client. There is probably a way to do this in one line.
Related
I'm using Cursive and I set aliases to dev, when I run the REPL it does not load the namespace that defined in deps configuration file:
:aliases {:dev {:main-opts ["--init" "src/my/server/core.clj"
"--eval" "(my.server.core/-main)"]}}
I tried this at the command-line and it worked as expected, loading my.server.core and then running its -main function, so I suspect that Cursive is using -R on aliases rather than -A so it is only pulling in :extra-deps and not :main-opts (that's just a guess, I don't use Cursive). My best suggestion is to ask in the #cursive channel on the Clojurians Slack as that is the primary channel for Cursive support (as far as I know).
I'll also highlight Krisztian's comment that you could use "-m" "my.server.core" as your entire :main-opts since -m will load the namespace and run the -main within it.
However, those options are not the same as Leiningen's :init-ns -- what I think you need is:
{:aliases {:dev {:main-opts ["-e" "(require,'my.server.core)"
"-e" "(in-ns,'my.server.core)"]}}}
When you specify :main-opts, that will suppress starting a REPL:
$ clj -A:dev
#object[clojure.lang.Namespace 0x3dddbe65 "my.server.core"]
$
So you need to add -r to tell the Clojure CLI that you also want a REPL started:
clj -A:dev -r
#object[clojure.lang.Namespace 0x433ffad1 "my.server.core"]
my.server.core=> (doc -main)
-------------------------
my.server.core/-main
([& args])
I don't do a whole lot ... yet.
nil
my.server.core=>
I'm trying out spyscope, and following the documented example, I'm getting:
user=> (take 20 (repeat #spy/d (+ 1 2 3)))
RuntimeException No reader function for tag spy/d clojure.lang.LispReader$CtorReader.readTagged (LispReader.java:1245)
RuntimeException Unmatched delimiter: ) clojure.lang.Util.runtimeException (Util.java:221)
RuntimeException Unmatched delimiter: ) clojure.lang.Util.runtimeException (Util.java:221)
My ~/.lein/profile.clj is:
{:user {:dependencies [[spyscope "0.1.6"]]
:injections [(require 'spyscope.core)
(use 'clojure.tools.trace)]
:plugins [[lein-try "0.4.3"]]
}
}
My version of Leiningen is:
$ lein --version
Leiningen 2.8.1 on Java 1.8.0_212 OpenJDK 64-Bit Server VM
I can't seem to find any answers on how to resolve this.
Answering my own question to make it easier for the next person to looking for the solution.
The answer can be traced to [this issue]: (https://github.com/dgrnbrg/spyscope/issues/8)
Lein 2 allows users to fire lein repl in a non project directory and that's the case
You have to use spyscope within a directory with a project.clj file.
You can use spyscope this way at your profiles.clj
; try/catch to workaround an issue where `lein repl` outside a project dir
; will not load reader literal definitions correctly:
(try (require 'spyscope.core)
(catch RuntimeException e))
Suppose that I have implemented a few functions for some personal calculation at work. I'd like to build a .jar (uberjar) that my colleagues would use too in a REPL, like:
megacorpcalcs.core=> (+ 2 2)
4
megacorpcalcs.core=> (salary 8 0.4)
666$
What code should I type for a REPL to start when the .jar launches?
EDIT: after your comments I've split this answer into 2
1. Running your uberjar with a REPL
Create your uberjar, and start it with:
java -cp /path/to/your/application-X.Y.Z-standalone.jar clojure.main -i #your_application/foo.clj -r
I had to add the -i parameter and point it to one of my clj files in order to get any of my classes in the project to actually load in the repl. There may be a better way to do this, but I haven't found it yet. Without it, you get a standard clojure repl but your application isn't loaded.
Note, you need the # symbol so that it loads from the jar file relative to the classpath (i.e from root of jar).
This should start a repl which you can change namespace and run your application functions in.
Additionally, you can install rlwrap and prepend the java command with it so you can use history and arrow keys sanely.
2. Embedding a REPL server in your application to connect to from another client
You can embed your own repl on startup of your application (e.g. a simple main that just starts a repl instance), and then your users can run your jar file, and separately connect to it with their choice of tool (cider-jack-in, 'lein repl connect ...')
The simple version of this is:
(start-server :port 7890 :handler cider-nrepl-handler)
Substitute the port you want, see below for the appropriate namespaces to import.
Here is a more complete example:
(ns your-app.server
(:gen-class)
(:require [cider.nrepl :refer (cider-nrepl-handler)]
[clojure.tools.nrepl.server :refer [start-server]]))
(def repl-server (atom nil))
(defn create-nrepl-server!
[repl-port]
(println (format "starting nrepl server on port %d" repl-port))
(reset! repl-server (start-server :port repl-port :handler cider-nrepl-handler)))
(defn -main []
;; ...
(let [repl-port 7890]
(create-nrepl-server! repl-port)
(spit ".nrepl-port" repl-port)))
You'll need the following in your project.clj file
:plugins [[cider/cider-nrepl "0.10.0"]] ;; or whatever version you prefer
:dependencies [[org.clojure/tools.nrepl "0.2.12"]]
Once connected to your custom repl, standard rules apply, just change namespace and call your functions.
I spent some time last night messing with my leinigen profiles.clj to get rid of all the errors that were being printed when starting cider in my project. Today I went to start a repl from the terminal (I like to keep one open while I work) but it didn't work. I thought it was a cider issue so I tried it from Emacs but even in Emacs if I'm not in a project the repl won't start.
Here's the error:
Error loading refactor-nrepl.middleware: clojure.lang.ArityException: Wrong number of args (4) passed to: StringReader, compiling:(abnf.clj:186:28)
Exception in thread "Thread-4" java.lang.RuntimeException: Unable to resolve var: refactor-nrepl.middleware/wrap-refactor in this context, compiling:(NO_SOURCE_PATH:0:0)
...
Caused by: java.lang.RuntimeException: Unable to resolve var: refactor-nrepl.middleware/wrap-refactor in this context
My ~/.lein/profiles.clj
{:user {:plugins [[lein-try "0.4.3"]
[refactor-nrepl "1.1.0"]
[cider/cider-nrepl "0.9.1"]]
:dependencies [[org.clojure/tools.nrepl "0.2.12"]
[acyclic/squiggly-clojure "0.1.4"]
^:replace [org.clojure/tools.nrepl "0.2.12"]
[refactor-nrepl "1.1.0"]]}}
The versions of things when cider starts in a project
; CIDER 0.9.1 (Java 1.8.0_45, Clojure 1.7.0, nREPL 0.2.12)
I'm still pretty new to Clojure, Leinigen, Emacs, etc so I'm not sure why everything above made made my cider errors go away but it did. The cider errors I was getting were having to do with the nrepl version being too low and not having certain things installed (like refactor-nrepl).
When starting a repl from lein using lein repl, it really wants to run in a lein project dir. I keep an empty lein project named clj around in my home dir for this purpose. That way, my common dependencies are already there in the project.clj file, and lein is pre-configured just the way I like it.
You can start lein repl in an empty dir, but you get 10-20 error messages each time before it starts.
Another way is to use the plain repl built into the clojure jar file:
~/dummy > cp /home/alan/.m2/repository/org/clojure/clojure/1.8.0-RC1/clojure-1.8.0-RC1.jar .
~/dummy > d *
-rw-rw-r-- 1 alan alan 3935726 Nov 19 14:11 clojure-1.8.0-RC1.jar
~/dummy > java -jar clojure-1.8.0-RC1.jar
Clojure 1.8.0-RC1
user=>
As you can see, I created an empty directory named dummy and copied in the clojure-*.jar file. You can then run it with the syntax java -jar xxx.jar and it will fire up a repl completely independently of lein.
I also just keep a scratch project which I use for quick/simple repl sessions. There is a lien-oneoff plugin which is supposed to make it easy to work with simple single file lein projects which might be useful.
The other thing you could do is setup a boot config for basically getting a repl up to work with
what is your lein version, I am use 2.5.3, I can start lein repl anywhere.
Shell:~ >: lein repl
nREPL server started on port 52343 on host 127.0.0.1 - nrepl://127.0.0.1:52343
REPL-y 0.3.7, nREPL 0.2.10
Clojure 1.7.0
Java HotSpot(TM) 64-Bit Server VM 1.8.0_60-b27
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=> Bye for now!
Shell:~ >: lein version
Leiningen 2.5.3 on Java 1.8.0_60 Java HotSpot(TM) 64-Bit Server VM
Shell:~ >: cat .lein/profiles.clj
{:1.2 {:dependencies [[org.clojure/clojure "1.2.0"]]}
:1.3 {:dependencies [[org.clojure/clojure "1.3.0"]]}
:1.4 {:dependencies [[org.clojure/clojure "1.4.0"]]}
:user {:plugins [[lein-immutant "2.0.0-alpha2"]
[lein-clojars "0.9.1"]
[lein-ancient "0.5.5"]
[lein-kibit "0.0.8"]
[lein-try "0.4.3"]
[venantius/ultra "0.2.0"]]
:ultra {:color-scheme :solarized_dark}}}
Is there some built-in functionality or plugin to lein to get a lein console, so for example one could test without waiting every time for JVM to start up.
$ lein console
>>> test
...
>>> test
...
>>> jar
Note: I'd like to trigger test runs myself, not e.g. by watching source files. That's why I'd like to have a lein console.
Clarification: I'm not looking for lein repl. I'd like to have a console where I could run lein task commands.
Older versions of leiningen used to include lein interactive, which behaved much like the feature you are asking for: it opened a shell into which you could type test and have it run lein test from the already-running lein jvm, and so on. This feature was removed in the transition to lein 2.0, I think, and although I don't know why I suspect there was a good reason. Maybe try asking in #leiningen on freenode?
You might want to have a look at grenchman. While it's not a Leiningen console it at least enables reusing of an existing REPL session. From what I gather, usage is as follows:
Move somewhere that is not inside a project and call:
$ lein repl :headless
Within your project directory, use:
$ grench lein <task> <options>
Tasks will be run inside the already spun up Leiningen JVM and the startup overhead should disappear.
Building grenchman seems to be tedious, though, and it is recommended to use one of the precompiled binaries (BUT they are currently not available).
And finally, that page also states:
Grenchman is still very new and may not be fully reliable.
So, good luck, I guess?
One option is to run a repl from leiningen's own jar file.
$ java -cp ~/.lein/self-installs/leiningen-2.5.0-standalone.jar clojure.main
Clojure 1.6.0
user=> (require '[leiningen.core.project :as project] '[leiningen.test :as test])
nil
user=> (def prj (project/read))
#'user/prj
user=> (test/test prj)
lein test org.noisesmith.orsos.load-test
Ran 3 tests containing 3 assertions.
0 failures, 0 errors.
nil
user=> (require '[leiningen.jar :as jar])
nil
user=> (jar/jar prj 'org.noisesmith.orsos)
Compiling org.noisesmith.orsos
Created /media/justin/806084F16084EEEA/clojure/orsos/target/orsos-0.1.0-SNAPSHOT.jar
{[:extension "jar"] "/media/justin/806084F16084EEEA/clojure/orsos/target/orsos-0.1.0-SNAPSHOT.jar"}
user=>
As a baseline, this can run lein tasks without having to restart lein every time. If you also use rlwrap or use nrepl it becomes a bit more usable. As far as I know there is no user friendly tooling around this (though there easily could be).
If you wish to use tasks from lein plugins those can be added to the -cp arg.