Skip to content

Commit

Permalink
Support clj-reload workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
filipesilva committed Feb 23, 2024
1 parent 3824d72 commit 87377e2
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .clj-kondo/nubank/matcher-combinators/config.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{:linters
{:unresolved-symbol
{:exclude [(cljs.test/is [match? thrown-match?])
(clojure.test/is [match? thrown-match?])]}}}
5 changes: 5 additions & 0 deletions .clj-kondo/rewrite-clj/rewrite-clj/config.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{:lint-as
{rewrite-clj.zip/subedit-> clojure.core/->
rewrite-clj.zip/subedit->> clojure.core/->>
rewrite-clj.zip/edit-> clojure.core/->
rewrite-clj.zip/edit->> clojure.core/->>}}
1 change: 1 addition & 0 deletions .eastwood
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1708718294690
1 change: 1 addition & 0 deletions .enrich-classpath-lein-repl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
java -cp /Users/filipesilva/work/cider-nrepl/test/spec:/Users/filipesilva/work/cider-nrepl/test/clj:/Users/filipesilva/work/cider-nrepl/test/cljs:/Users/filipesilva/work/cider-nrepl/test/common:/Users/filipesilva/work/cider-nrepl/test/src:/Users/filipesilva/work/cider-nrepl/src:/Users/filipesilva/work/cider-nrepl/test/resources:/Users/filipesilva/work/cider-nrepl/dev-resources:/Users/filipesilva/work/cider-nrepl/resources:/Users/filipesilva/work/cider-nrepl/target/classes:/Users/filipesilva/.m2/repository/org/slf4j/slf4j-api/2.0.4/slf4j-api-2.0.4.jar:/Users/filipesilva/.m2/repository/org/nrepl/incomplete/0.1.0/incomplete-0.1.0.jar:/Users/filipesilva/.m2/repository/org/tcrawley/dynapath/1.0.0/dynapath-1.0.0.jar:/Users/filipesilva/.m2/repository/ch/qos/logback/logback-core/1.3.7/logback-core-1.3.7.jar:/Users/filipesilva/.m2/repository/commons-io/commons-io/2.6/commons-io-2.6.jar:/Users/filipesilva/.m2/repository/com/cognitect/transit-java/1.0.371/transit-java-1.0.371.jar:/Users/filipesilva/.m2/repository/org/apache/maven/maven-repository-metadata/3.6.1/maven-repository-metadata-3.6.1.jar:/Users/filipesilva/.m2/repository/org/apache/httpcomponents/httpclient/4.5.13/httpclient-4.5.13.jar:/Users/filipesilva/.m2/repository/mx/cider/haystack/0.3.3/haystack-0.3.3.jar:/Users/filipesilva/.m2/repository/org/apache/maven/wagon/wagon-http-shared/3.3.4/wagon-http-shared-3.3.4.jar:/Users/filipesilva/.m2/repository/org/clojure/core.specs.alpha/0.2.56/core.specs.alpha-0.2.56.jar:/Users/filipesilva/.m2/repository/org/apache/maven/resolver/maven-resolver-spi/1.3.3/maven-resolver-spi-1.3.3.jar:/Users/filipesilva/.m2/repository/org/projectodd/shimdandy/shimdandy-impl/1.2.1/shimdandy-impl-1.2.1.jar:/Users/filipesilva/.m2/repository/org/apache/maven/wagon/wagon-http/3.3.4/wagon-http-3.3.4.jar:/Users/filipesilva/.m2/repository/org/codehaus/plexus/plexus-utils/3.2.0/plexus-utils-3.2.0.jar:/Users/filipesilva/.m2/repository/cljfmt/cljfmt/0.9.2/cljfmt-0.9.2.jar:/Users/filipesilva/.m2/repository/cider/orchard/0.22.0/orchard-0.22.0.jar:/Users/filipesilva/.m2/repository/org/apache/maven/resolver/maven-resolver-transport-http/1.3.3/maven-resolver-transport-http-1.3.3.jar:/Users/filipesilva/.m2/repository/leiningen-core/leiningen-core/2.9.10/leiningen-core-2.9.10.jar:/Users/filipesilva/.m2/repository/mvxcvi/puget/1.3.4/puget-1.3.4.jar:/Users/filipesilva/.m2/repository/org/apache/httpcomponents/httpcore/4.4.13/httpcore-4.4.13.jar:/Users/filipesilva/.m2/repository/org/apache/maven/wagon/wagon-provider-api/3.3.4/wagon-provider-api-3.3.4.jar:/Users/filipesilva/.m2/repository/com/cognitect/transit-clj/1.0.333/transit-clj-1.0.333.jar:/Users/filipesilva/.m2/repository/org/clojure/tools.macro/0.1.5/tools.macro-0.1.5.jar:/Users/filipesilva/.m2/repository/org/apache/maven/maven-resolver-provider/3.6.1/maven-resolver-provider-3.6.1.jar:/Users/filipesilva/.m2/repository/org/clojure/clojurescript/1.11.60/clojurescript-1.11.60.jar:/Users/filipesilva/.m2/repository/boot/pod/2.8.3/pod-2.8.3.jar:/Users/filipesilva/.m2/repository/org/clojure/test.check/1.1.1/test.check-1.1.1.jar:/Users/filipesilva/.m2/repository/mvxcvi/arrangement/2.1.0/arrangement-2.1.0.jar:/Users/filipesilva/.m2/repository/boot/base/2.8.3/base-2.8.3.jar:/Users/filipesilva/.m2/repository/org/apache/maven/resolver/maven-resolver-api/1.3.3/maven-resolver-api-1.3.3.jar:/Users/filipesilva/.m2/repository/org/clojure/google-closure-library-third-party/0.0-20211011-0726fdeb/google-closure-library-third-party-0.0-20211011-0726fdeb.jar:/Users/filipesilva/.m2/repository/timofreiberg/bultitude/0.3.0/bultitude-0.3.0.jar:/Users/filipesilva/.m2/repository/org/clojure/core.rrb-vector/0.1.2/core.rrb-vector-0.1.2.jar:/Users/filipesilva/.m2/repository/org/apache/maven/maven-model-builder/3.6.1/maven-model-builder-3.6.1.jar:/Users/filipesilva/.m2/repository/ch/qos/logback/logback-classic/1.3.7/logback-classic-1.3.7.jar:/Users/filipesilva/.m2/repository/com/googlecode/java-diff-utils/diffutils/1.3.0/diffutils-1.3.0.jar:/Users/filipesilva/.m2/repository/org/apache/maven/resolver/maven-resolver-transport-file/1.3.3/maven-resolver-transport-file-1.3.3.jar:/Users/filipesilva/.m2/repository/org/codehaus/plexus/plexus-component-annotations/1.7.1/plexus-component-annotations-1.7.1.jar:/Users/filipesilva/.m2/repository/org/clojure/tools.namespace/1.3.0/tools.namespace-1.3.0.jar:/Users/filipesilva/.m2/repository/org/codehaus/plexus/plexus-interpolation/1.25/plexus-interpolation-1.25.jar:/Users/filipesilva/.m2/repository/nrepl/nrepl/1.0.0/nrepl-1.0.0.jar:/Users/filipesilva/.m2/repository/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1.jar:/Users/filipesilva/.m2/repository/javax/xml/bind/jaxb-api/2.4.0-b180830.0359/jaxb-api-2.4.0-b180830.0359.jar:/Users/filipesilva/.m2/repository/compliment/compliment/0.5.1/compliment-0.5.1.jar:/Users/filipesilva/.m2/repository/javax/activation/javax.activation-api/1.2.0/javax.activation-api-1.2.0.jar:/Users/filipesilva/.m2/repository/org/javassist/javassist/3.18.1-GA/javassist-3.18.1-GA.jar:/Users/filipesilva/.m2/repository/org/apache/maven/resolver/maven-resolver-impl/1.3.3/maven-resolver-impl-1.3.3.jar:/Users/filipesilva/.m2/repository/org/apache/maven/maven-artifact/3.6.1/maven-artifact-3.6.1.jar:/Users/filipesilva/.m2/repository/nubank/matcher-combinators/3.8.8/matcher-combinators-3.8.8.jar:/Users/filipesilva/.m2/repository/cider/piggieback/0.5.3/piggieback-0.5.3.jar:/Users/filipesilva/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.15.2/jackson-core-2.15.2.jar:/Users/filipesilva/.m2/repository/javax/inject/javax.inject/1/javax.inject-1.jar:/Users/filipesilva/.m2/repository/robert/hooke/1.3.0/hooke-1.3.0.jar:/Users/filipesilva/.m2/repository/com/google/errorprone/error_prone_annotations/2.11.0/error_prone_annotations-2.11.0.jar:/Users/filipesilva/.m2/repository/org/apache/maven/resolver/maven-resolver-util/1.3.3/maven-resolver-util-1.3.3.jar:/Users/filipesilva/.m2/repository/mx/cider/logjam/0.2.0/logjam-0.2.0.jar:/Users/filipesilva/.m2/repository/org/apache/maven/maven-model/3.6.1/maven-model-3.6.1.jar:/Users/filipesilva/.m2/repository/com/google/javascript/closure-compiler-unshaded/v20220502/closure-compiler-unshaded-v20220502.jar:/Users/filipesilva/.m2/repository/org/clojure/java.classpath/1.0.0/java.classpath-1.0.0.jar:/Users/filipesilva/.m2/repository/org/jsoup/jsoup/1.12.1/jsoup-1.12.1.jar:/Users/filipesilva/.m2/repository/rewrite-clj/rewrite-clj/1.1.45/rewrite-clj-1.1.45.jar:/Users/filipesilva/.m2/repository/org/slf4j/slf4j-nop/1.7.25/slf4j-nop-1.7.25.jar:/Users/filipesilva/.m2/repository/org/clojure/clojure/1.10.3/clojure-1.10.3.jar:/Users/filipesilva/.m2/repository/instaparse/instaparse/1.4.12/instaparse-1.4.12.jar:/Users/filipesilva/.m2/repository/org/apache/maven/resolver/maven-resolver-connector-basic/1.3.3/maven-resolver-connector-basic-1.3.3.jar:/Users/filipesilva/.m2/repository/com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1.jar:/Users/filipesilva/.m2/repository/org/clojure/spec.alpha/0.2.194/spec.alpha-0.2.194.jar:/Users/filipesilva/.m2/repository/org/apache/maven/maven-builder-support/3.6.1/maven-builder-support-3.6.1.jar:/Users/filipesilva/.m2/repository/org/msgpack/msgpack/0.6.12/msgpack-0.6.12.jar:/Users/filipesilva/.m2/repository/boot/core/2.8.3/core-2.8.3.jar:/Users/filipesilva/.m2/repository/thunknyc/profile/0.5.2/profile-0.5.2.jar:/Users/filipesilva/.m2/repository/org/clojure/google-closure-library/0.0-20211011-0726fdeb/google-closure-library-0.0-20211011-0726fdeb.jar:/Users/filipesilva/.m2/repository/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar:/Users/filipesilva/.m2/repository/clj-commons/pomegranate/1.2.1/pomegranate-1.2.1.jar:/Users/filipesilva/.m2/repository/org/apache/maven/resolver/maven-resolver-transport-wagon/1.3.3/maven-resolver-transport-wagon-1.3.3.jar:/Users/filipesilva/.m2/repository/io/github/tonsky/clj-reload/0.2.0/clj-reload-0.2.0.jar:/Users/filipesilva/.m2/repository/org/projectodd/shimdandy/shimdandy-api/1.2.0/shimdandy-api-1.2.0.jar:/Users/filipesilva/.m2/repository/org/flatland/classlojure/0.7.1/classlojure-0.7.1.jar:/Users/filipesilva/.m2/repository/org/rksm/suitable/0.6.2/suitable-0.6.2.jar:/Users/filipesilva/.m2/repository/org/clojure/tools.cli/1.0.214/tools.cli-1.0.214.jar:/Users/filipesilva/.m2/repository/org/clojure/tools.trace/0.7.11/tools.trace-0.7.11.jar:/Users/filipesilva/.m2/repository/com/hypirion/io/0.3.1/io-0.3.1.jar:/Users/filipesilva/.m2/repository/org/clojure/tools.reader/1.3.6/tools.reader-1.3.6.jar:/Users/filipesilva/.m2/repository/org/clojure/math.combinatorics/0.2.0/math.combinatorics-0.2.0.jar:/Users/filipesilva/.m2/repository/fipp/fipp/0.6.26/fipp-0.6.26.jar:/Users/filipesilva/.m2/repository/commons-codec/commons-codec/1.15/commons-codec-1.15.jar:/Users/filipesilva/.cache/mx.cider/enrich-classpath/2101/1110603317/992118986.jar:/Users/filipesilva/work/cider-nrepl/test/java:/Users/filipesilva/.cache/mx.cider/unzipped-jdk-sources/2101:/opt/homebrew/Cellar/openjdk/21.0.1/libexec/openjdk.jdk/Contents/Home/lib/src.zip -Djava.util.logging.config.file=test/resources/logging.properties -Dcider.internal.testing=true -Dclojure.compile.path=/Users/filipesilva/work/cider-nrepl/target/classes --add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED clojure.main --eval "(try (set! *assert* true) (catch java.lang.Throwable e (.printStackTrace e)))" -m nrepl.cmdline
Empty file added .make_kondo_prep
Empty file.
47 changes: 47 additions & 0 deletions doc/modules/ROOT/pages/nrepl-api/ops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,53 @@ Returns::
{blank}



=== `reload`

Reloads all changed files in dependency order, using clj-reload.

Required parameters::
{blank}

Optional parameters::
* `:nrepl.middleware.print/buffer-size` The size of the buffer to use when streaming results. Defaults to 1024.
* `:nrepl.middleware.print/keys` A seq of the keys in the response whose values should be printed.
* `:nrepl.middleware.print/options` A map of options to pass to the printing function. Defaults to ``nil``.
* `:nrepl.middleware.print/print` A fully-qualified symbol naming a var whose function to use for printing. Must point to a function with signature [value writer options].
* `:nrepl.middleware.print/quota` A hard limit on the number of bytes printed for each value.
* `:nrepl.middleware.print/stream?` If logical true, the result of printing each value will be streamed to the client over one or more messages.


Returns::
* `:error` A sequence of all causes of the thrown exception when ``status`` is ``:error``.
* `:progress` Description of current namespace being unloaded/loaded.
* `:status` ``:ok`` if reloading was successful; otherwise ``:error``.



=== `reload-all`

Reloads all files in dependency order, using clj-reload.

Required parameters::
{blank}

Optional parameters::
* `:nrepl.middleware.print/buffer-size` The size of the buffer to use when streaming results. Defaults to 1024.
* `:nrepl.middleware.print/keys` A seq of the keys in the response whose values should be printed.
* `:nrepl.middleware.print/options` A map of options to pass to the printing function. Defaults to ``nil``.
* `:nrepl.middleware.print/print` A fully-qualified symbol naming a var whose function to use for printing. Must point to a function with signature [value writer options].
* `:nrepl.middleware.print/quota` A hard limit on the number of bytes printed for each value.
* `:nrepl.middleware.print/stream?` If logical true, the result of printing each value will be streamed to the client over one or more messages.


Returns::
* `:error` A sequence of all causes of the thrown exception when ``status`` is ``:error``.
* `:progress` Description of current namespace being unloaded/loaded.
* `:status` ``:ok`` if reloading was successful; otherwise ``:error``.



=== `resource`

Obtain the path to a resource.
Expand Down
1 change: 1 addition & 0 deletions project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
~(with-meta '[org.clojure/tools.namespace "1.3.0"]
;; :cognitest uses tools.namespace, so we cannot inline it while running tests.
{:inline-dep (not= "true" (System/getenv "SKIP_INLINING_TEST_DEPS"))})
^:inline-dep [io.github.tonsky/clj-reload "0.2.0"]
^:inline-dep [org.clojure/tools.trace "0.7.11"]
^:inline-dep [org.clojure/tools.reader "1.3.6"]
[mx.cider/logjam "0.2.0"]]
Expand Down
17 changes: 17 additions & 0 deletions src/cider/nrepl.clj
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,23 @@ if applicable, and re-render the updated value."
"refresh-clear"
{:doc "Clears the state of the refresh middleware. This can help recover from a failed load or a circular dependency error."}}})

(def-wrapper wrap-refresh cider.nrepl.middleware.reload/handle-reload
{:doc "Reload middleware."
:requires #{"clone" #'wrap-print}
:handles {"cider.clj-reload/reload"
{:doc "Reloads all changed files in dependency order,
using the io.github.tonsky/clj-reload library. It is bundled with cider-nrepl.
If that dependency is already in present your project and clj-reload.core/init has been invoked beforehand,
those configured directories will be honored."
:returns {"progress" "Description of current namespace being unloaded/loaded."
"status" "`:ok` if reloading was successful; otherwise `:error`."
"error" "A sequence of all causes of the thrown exception when `status` is `:error`."}}
"cider.clj-reload/reload-all"
{:doc "Reloads all files in dependency order."
:returns {"reloading" "Description of current namespace being unloaded/loaded."
"status" "`:ok` if reloading was successful; otherwise `:error`."
"error" "A sequence of all causes of the thrown exception when `status` is `:error`."}}}})

(def-wrapper wrap-resource cider.nrepl.middleware.resource/handle-resource
{:doc "Middleware that provides the path to resource."
:handles {"resource"
Expand Down
50 changes: 50 additions & 0 deletions src/cider/nrepl/middleware/reload.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
(ns cider.nrepl.middleware.reload
(:require
[clj-reload.core :as reload]
[clojure.main :refer [repl-caught]]
[clojure.string :as str]
[haystack.analyzer :as analyzer]
[nrepl.middleware.interruptible-eval :refer [*msg*]]
[nrepl.middleware.print :as print]
[nrepl.misc :refer [response-for]]
[nrepl.transport :as transport]
[orchard.misc :as misc]))

(defn- user-reload
"clj-reload.core/reload from the user project.
Must be configured via clj-reload.core/init before being called."
[]
(some-> (symbol "clj-reload.core" "reload") ;; Don't use mrandorsenized version
resolve))

(defn respond
[{:keys [transport] :as msg} response]
(transport/send transport (response-for msg response)))

(defn- refresh-reply
[{:keys [::print/print-fn transport session id] :as msg}]
(let [{:keys [exec]} (meta session)]
(exec id
(fn []
(try
(let [reload (or (user-reload) reload/reload)]
(reload (cond-> {:log-fn (fn [& args]
(respond msg {:progress (str/join " " args)}))}
(:all msg) (assoc :only :all)))
(respond msg {:status :ok}))
(catch Throwable error
(respond msg {:status :error
;; TODO assoc :file, :line info if available
:error (analyzer/analyze error print-fn)})
(binding [*msg* msg
*err* (print/replying-PrintWriter :err msg {})]
(repl-caught error)))))

(fn [] (respond msg {:status :done})))))

(defn handle-reload [handler msg]
(case (:op msg)
"cider.clj-reload/reload" (refresh-reply msg)
"cider.clj-reload/reload-all" (refresh-reply (assoc msg :all true))
(handler msg)))

36 changes: 36 additions & 0 deletions test/clj/cider/nrepl/middleware/reload_test.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
(ns cider.nrepl.middleware.reload-test
(:require
[cider.nrepl.middleware.reload :as rl]
[cider.nrepl.test-session :as session]
[clj-reload.core :as reload]
[clojure.test :refer :all]))

(use-fixtures :each session/session-fixture)

(def ^:private dirs-to-reload
;; Limit the scope of what we reload, because (for example) reloading the
;; cider.nrepl.middleware.test-session ns causes *session* in that ns to be
;; unloaded, which breaks session-fixture, and hence all of the below tests.
["test/clj/cider/nrepl/middleware/util"])

(reload/init {:dirs dirs-to-reload})

(deftest user-reload
(testing "returns nil if clojure.tools.namespace isn't loaded"
(with-redefs [resolve (constantly nil)]
(is (nil? (#'rl/user-reload))))))

(deftest reload-op-test
(testing "reload op works"
(let [response (session/message {:op "cider.clj-reload/reload"})]
;; There is nothing to reload since the files did not change,
;; but the message does come from clj-reload.core/reload.
(is (= "Nothing to reload" (:progress response)))
(is (= #{"done" "ok"} (:status response))))))

(deftest reload-all-op-test
(testing "reload-all op works"
(let [response (session/message {:op "cider.clj-reload/reload-all"})]
(is (seq (:progress response)))
(is (= #{"done" "ok"} (:status response))))))

0 comments on commit 87377e2

Please sign in to comment.