How to hot reload a namespace on file save in Leiningen REPL - clojure

When using the leiningen REPL, is there a way to make a file or ns automatically reload in the repl on file save. Currently I reload the ns by typing the following in the repl - (use 'sample.ns :reload-all).
However can I have it reload automatically on file save ?

You can easily reuse the code from duct framework.
You will need only hawk files watcher.
Here is how it can be looks like:
(defn- clojure-file? [_ {:keys [file]}]
(re-matches #"[^.].*(\.clj|\.edn)$" (.getName file)))
(defn- auto-reset-handler [ctx event]
(binding [*ns* *ns*]
(clojure.tools.namespace.repl/refresh)
ctx))
(defn auto-reset
"Automatically reset the system when a Clojure or edn file is changed in
`src` or `resources`."
[]
(hawk.core/watch! [{:paths ["src/" "resources/" "dev/src/" "dev/resources/"]
:filter clojure-file?
:handler auto-reset-handler}]))

Clojure-Watch library does what you need. It observes a file and performs some action. In your case, an action would be to reload a namespace from that file. Also, it requires to write some initial code to launch the observer.
This way seems a bit complicated to me. Plain REPL launched directly from Lein is not effective way to develop. You better to use some Clojure-friendly editor like Emacs or Lightable.

Most major editors support custom hotkey bindings and have a Clojure plugin that allows you to connect to the active REPL over the network (via "nREPL"). Personally, I use vim and therefore use vim-fireplace for this purpose.
This means you can have a custom hotkey for reloading whatever file you're editing as you edit it. From there, it's typically trivial to add a custom on-save hook that does the reloading.

Related

How can I stop jetty server without restarting repl

Let's say I have a trivial boot-clj task that uses '[pandeiro.boot-http :refer [serve]]. If I make changes and need to restart the task it would complain that the port is already in use. Is there a way to kill jetty server without having to restart repl?
If you want only this many people use this pattern:
(defonce running-server (atom nil))
(defn stop-server [] (#running-server))
(defn go []
(reset! running-server
(org.httpkit.server/run-server
... your stuff here ...))
If this is a longer term project starting with something like the component framework solves this problem in a much more elegant way and allows for many dependent components (hence the name). This is a good place to get started and worth reading before starting your next project.
pandeiro.boot-http supports reloading of your handler so you don't have to restart the serve task. You need to configure it with :reload set to true:
On command line:
boot serve -H myapp.server/app -R wait
Or in your boot script:
(boot (serve :handler 'myapp.server/app :reload true) (wait))
For regular static files serve always returns the current version from the disk so there is no need for reloading for them.
If you really need to restart the task I guess you might be affected by issue in pandeiro.boot-http and might need to contact its maintainer.

How to do integration testing for clojure/ring/selenium/leiningen?

I have a clojure/ring web application which I want to test with clj-webdriver. Is there a simple way to run the ring webserver and then run the tests such that they target the ring instance?
I'm thinking of a usage something like:
$ lein with-ring test
I have two ideas so far:
write a custom higher order leiningen plugin. Seems too complicated. Does a similar plugin already exist?
write a Makefile rule which starts ring, runs lein test, find&kill the ring process - too complicated/hacky
Is there a simpler way?
If you're using clojure.test you can call use-fixtures to start/stop your server from within the tests, e.g.:
(use-fixtures
:once
(fn [f]
(let [server (ring.adapter.jetty/run-jetty
#'your-app
{:port 1234 :join? false})]
(try
(f)
(finally
(.stop server))))))
Just adjust start/stop logic to your preferred webserver (jetty in this example; http-kit would be very similar). If you replace :once with :each you'll even have a fresh server instance for each single test.

Forcing Cake to reload functions from my .clj files

I'm new to Clojure, and after too much of my life have been already wasted on waiting for Leiningen to run my code, I'm trying to move to Cake. While Cake's persistent JVM loads up blazing fast - it presents a bigger problem - my functions are also persistent!
To demonstrate the problem, I've started a cake project(using cake new mess-up-with-cake), and wrote this in core.clj:
(ns mess-up-with-cake.core)
(defn main-function[]
(println "I'm in the main function")
)
(println "I'm in core.clj, not inside in any function")
And this is project.clj:
(defproject mess-up-with-cake "0.0.1-SNAPSHOT"
:description "TODO: add summary of your project"
:dependencies [[clojure "1.2.0"]])
(use 'mess-up-with-cake.core)
(deftask my-task
(println "I'm in my task")
(main-function)
)
When running it with cake my-task, I get:
I'm in core.clj, not inside in any function
I'm in my task
I'm in the main function
No surprise here.
Now, I've changed core.clj to this:
(ns mess-up-with-cake.core)
(defn main-function[]
(println "I'm in the main function")
(println "I've made a change in the main function")
)
(println "I'm in core.clj, not inside in any function")
(println "I've made a change outside the main function")
And when I run it, I get
I'm in core.clj, not inside in any function
I've made a change outside the main function
I'm in my task
I'm in the main function
core.clj was clearly reloaded, but the change I've made inside the main function was not printed! Only when I stop the JVM with cake kill and rerun it I get the desired result - but if I have to restart the JVM every time I change a function, I might as well go back to lein...
Any idea how to force cake to reload my functions(and only my functions - reloading the entire Clojure runtime + any libraries I'm using probably won't be much faster than restarting the JVM..)?
This may not directly answer your question, though I hope it helps:
It sounds like your workflow if you where using leiningen would be to run:
lein run
wait for the JVM to start up .... get bored ...
observe result
edit code
repeat
This is a very common pattern in most languages and it's occasionally used for Clojure development (and Cake is very helpful here). It is much more common for Clojure development to use a single instance of the project and connect the editor to that instance using nrepl (or Slime and Swank). Because most everyone leaves the project running while they do the development not many people feel this pain and so the solutions are not as good in my opinion. Cake has largely been merged into Leiningen and the future direction of the Cake project is not clear to me (I could very well be wrong on this point). Of the Clojureians I know, all of them have moved to Leiningen and connect to their project from an editor like Emacs or vim.
a common workflow is:
start Emacs
M-x nrepl-jack-in
Ctrl-c Crtl-l to reload all the namespace and all it's dependent namespaces (this is close to a solution to your problem)
hack, load, repeat ;-)
This workflow is not Emacs or VI specific, the same method is used from Eclipse and Intelij
re: " reloading the entire Clojure runtime + any libraries I'm using probably won't be much faster than restarting the JVM".
I find it to be no more than two seconds even with my larger projects
I used to struggle with the slow JVM startup speed as well, and had mixed success with Cake. You might want to take a look at the excellent autoexpect plugin for Leiningen, explained in some length in the author's blog post. Basically autoexpect reloads your code every time the working directory tree is updated (and evaluates any expect clause, reporting any test failures). Makes continuous testing a dream -- I sometimes have two shells going in Emacs -- one for the output of lein autoexpect, one for a connected REPL to send snippets of code to as the other poster is suggesting.
I like the continuous testing style so much I wrote a similar utility in Python for my non-Clojure development (described in this blog post) -- for Clojure, I use autoexpect.

Reloading code on a production ring-clojure server

What's the best way to push new code to a production ring server without restarting the whole JVM?
Currently I use wrap-reload in production, but this doesn't quite work for me because sometimes I want to run commands in the repl (doing database migrations for example) before ring starts handling requests with the new code. Also various blogs and tutorials out there say not to use wrap-reload in production, though I don't understand why not.
I have come up with the following solution, but I confess I don't have a deep understanding of what's going on under the hood. I was wondering if I could get a sanity check by someone who does. Does this technique seem reasonable?
The idea is to have a path (/admin/reload-clj) that causes all the clojure code to be reloaded.
(defonce ^:dynamic *jetty*)
(declare reload-clj)
(defn app [req]
...
(when (= (req :uri) "/admin/reload-clj") (reload-clj req))
...)
(defn start-jetty []
(let [j (run-jetty app {:port (http-port) :join? false :max-threads 16})]
(dosync (ref-set *jetty* j))
j))
(defn reload-clj [req]
(future
(log/info "Reloading clojure code...")
(require '(whrusrv admin main utils wdb) :reload-all)
(.stop #*jetty*)
(start-jetty)
(log/info "Clojure reload success!"))
{:status 200
:headers {"Content-Type" "text/plain"}
:body "Reloading..."})
(defn -main [& args]
(start-jetty))
The code you have will work, though you should be aware that :reload-all only loads a namespace and that namespaces dependencies. It does not recursively load dependencies of those namespaces.
I should add that reloading in this way is strongly not reccomended in a production system.
Newly deployed code might have errors that aren't apparent until the system is restarted (e.g, they depend on a var that is still defined from the running system but whose declaration was removed). The system will work fine but then fail on restart.
Loading code can also have side effects which could screw up your production environment. Although its good style to avoid these, the only way to truly be sure something unexpected won't happen is to do a JVM restart.
The best way to do a zero-downtime deploy on the JVM is a rolling deploy using a load balancer.
I had an intranet web service in common lisp at a previous job, so I don't know if that qualifies as production. Also, being in CL my answer is neither ring nor clojure specific. Still, it's useful for reloading code.
What I did is to start a swank server (part of slime) on the production lisp instance and connect to it even remotely from my desktop. That way I could write new code, rewrite code, debug, reload, etc. Obviously you'll have to be extra carefull in a real production system.
You can do similarly in clojure, you even have alternatives to swank, like nrepl.
You'll have to take security into account as well and allow only local connections, or whatever works for you.

Where's run-server gone in compojure?

I used to be able to start a web server in compojure like this:
(run-server {:port 8080} "/*" (servlet my-app))
Does anyone know where this function has gone in the latest compojure? (0.6.2)
The docs say I'm supposed to run it from the command line and use some freaky auto-reloading thing, at which point I might as well be using python.
You're looking at some seriously out-dated documentation.
For jetty, use
(use 'ring.adapter.jetty)
(defn start-web []
(run-jetty (var my-site) {:port 8080 :join? false}))
Where my-site is your top-level handler function.
You can call that function anywhere, including from the REPL in SLIME. Recompiling/redefining my-site will work on a running server, so there's no need for auto-reloading if you're already using an interactive environment.
EDIT: compojure has been split into ring & clout, with compojure itself remaining as a small selection of higher-level abstractions on top. Most of the actual server stuff and design documentation is now in ring. See https://github.com/mmcgrana/ring/wiki