From 70fd30527944d22487b576ac5909fa45fcac6c5b Mon Sep 17 00:00:00 2001 From: Toby Crawley Date: Mon, 31 Mar 2014 11:12:11 -0400 Subject: [PATCH] Update the logic for initing a repl on deploy [IMMUTANT-416] This change makes [:immutant :nrepl-port] override [:ring :nrepl]. The init now works like this: 1) if no repl config is provided, a repl on port 0 will start in dev mode 2) if [:ring :nrepl] is provided, the repl will only start if [:ring :nrepl :start?] 3) if [:immutant :nrepl-port] is set, it overrides [:ring :nrepl]. If it is `nil`, no repl will be started, even in dev mode. --- .../core/src/main/clojure/immutant/repl.clj | 59 ++++++++----- .../src/main/clojure/immutant/runtime.clj | 2 +- .../src/test/clojure/immutant/repl_test.clj | 88 +++++++++++++++++++ .../test/clojure/immutant/runtime_test.clj | 12 ++- 4 files changed, 134 insertions(+), 27 deletions(-) create mode 100644 modules/core/src/test/clojure/immutant/repl_test.clj diff --git a/modules/core/src/main/clojure/immutant/repl.clj b/modules/core/src/main/clojure/immutant/repl.clj index 603fbfe3..67e10704 100644 --- a/modules/core/src/main/clojure/immutant/repl.clj +++ b/modules/core/src/main/clojure/immutant/repl.clj @@ -26,6 +26,16 @@ (Integer. port) port)) +(defn ^:private spit-nrepl-files + [port file] + (doseq [f (map util/app-relative + (if file + [file] + [".nrepl-port" "target/repl-port"]))] + (.mkdirs (.getParentFile f)) + (spit f port) + (.deleteOnExit f))) + (defn stop-nrepl "Stops the given nrepl server." [server] @@ -69,33 +79,38 @@ :port (fix-port port) :bind interface-address)] (util/at-exit (partial stop-nrepl server)) + (let [ss (-> server deref :ss) + host (-> ss .getInetAddress .getHostAddress) + bound-port (.getLocalPort ss)] + (log/info "nREPL bound to" (str host ":" bound-port)) + (spit-nrepl-files bound-port (:nrepl-port-file (registry/get :config)))) server)))))) ([port] (start-nrepl nil port))) -(defn ^:private spit-nrepl-files - [port file] - (doseq [f (map util/app-relative - (if file - [file] - [".nrepl-port" "target/repl-port"]))] - (.mkdirs (.getParentFile f)) - (spit f port) - (.deleteOnExit f))) +(defn ^:private immutant-nrepl-config [config] + (if (some #{:nrepl-port :nrepl-interface} (keys config)) + (let [port (:nrepl-port config) + interface (:nrepl-interface config)] + {:port port + :interface interface + :start? (or port + interface + (not (contains? config :nrepl-port)))}))) + +(defn ^:private ring-nrepl-config [project] + (if-let [nrepl (-> project :ring :nrepl)] + (update-in nrepl [:start?] boolean))) (defn ^{:internal true :no-doc true} init-repl "Looks for nrepl-port value in the given config, and starts the appropriate servers." - [config] - (let [ring-nrepl-config (-> (registry/get :project) :ring :nrepl) - port (or (and (:start? ring-nrepl-config) - (:port ring-nrepl-config)) - (:nrepl-port config (and (nil? ring-nrepl-config) (util/dev-mode?) 0))) - interface (:nrepl-interface config)] - (if (or port interface) - (if-let [nrepl (start-nrepl interface (or port 0))] - (let [ss (-> nrepl deref :ss) - host (-> ss .getInetAddress .getHostAddress) - bound-port (.getLocalPort ss)] - (log/info "nREPL bound to" (str host ":" bound-port)) - (spit-nrepl-files bound-port (:nrepl-port-file config))))))) + [config project] + (let [cfg (merge + {:port 0 + :interface nil + :start? (util/dev-mode?)} + (ring-nrepl-config project) + (immutant-nrepl-config config))] + (when (:start? cfg) + (start-nrepl (:interface cfg) (:port cfg))))) diff --git a/modules/core/src/main/clojure/immutant/runtime.clj b/modules/core/src/main/clojure/immutant/runtime.clj index be4bd63a..311ff0b9 100644 --- a/modules/core/src/main/clojure/immutant/runtime.clj +++ b/modules/core/src/main/clojure/immutant/runtime.clj @@ -118,7 +118,7 @@ post-initialize is called to finalize initialization." (log/warn "No :init fn, immutant.init namespace or :ring options found for" (util/app-name) "- no initialization will be performed")) - (repl/init-repl (registry/get :config))) + (repl/init-repl (registry/get :config) (registry/get :project))) (defn ^{:internal true} set-app-config "Takes the full application config and project map as data strings diff --git a/modules/core/src/test/clojure/immutant/repl_test.clj b/modules/core/src/test/clojure/immutant/repl_test.clj new file mode 100644 index 00000000..0f5bb5b7 --- /dev/null +++ b/modules/core/src/test/clojure/immutant/repl_test.clj @@ -0,0 +1,88 @@ +;; Copyright 2008-2014 Red Hat, Inc, and individual contributors. +;; +;; This is free software; you can redistribute it and/or modify it +;; under the terms of the GNU Lesser General Public License as +;; published by the Free Software Foundation; either version 2.1 of +;; the License, or (at your option) any later version. +;; +;; This software is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public +;; License along with this software; if not, write to the Free +;; Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +;; 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +(ns immutant.repl-test + (:use immutant.repl + clojure.test) + (:require [immutant.util :as u])) + +(testing "init-repl" + (deftest repl-should-start-when-there-is-no-init-in-dev-mode + (let [passed-args (atom nil)] + (with-redefs [start-nrepl (fn [& args] (reset! passed-args args)) + u/dev-mode? (constantly true)] + (init-repl nil nil) + (is (= 0 (last @passed-args)))))) + +(deftest repl-should-not-start-when-there-is-no-init-in-!dev-mode + (let [started? (atom nil)] + (with-redefs [start-nrepl (fn [& _] (reset! started? true)) + u/dev-mode? (constantly false)] + (init-repl nil nil) + (is (not @started?))))) + +(deftest repl-should-not-start-when-port-is-explicitly-nil + (let [started? (atom nil)] + (with-redefs [start-nrepl (fn [& _] (reset! started? true)) + u/dev-mode? (constantly true)] + (init-repl {:nrepl-port nil} nil) + (is (not @started?))))) + +(deftest repl-should-use-given-port-and-interface-from-immutant-config + (let [passed-args (atom nil)] + (with-redefs [start-nrepl (fn [& args] (reset! passed-args args))] + (init-repl {:nrepl-port 1 :nrepl-interface :foo} nil) + (is (= [:foo 1] @passed-args))))) + +(deftest repl-should-honor-ring-repl-opts-when-no-immutant-repl-opts-given + (let [passed-args (atom nil)] + (with-redefs [start-nrepl (fn [& args] (reset! passed-args args))] + (init-repl nil {:ring {:nrepl {:port 1 :start? true}}}) + (is (= [nil 1] @passed-args))))) + +(deftest repl-should-honor-ring-repl-opts-when-no-immutant-repl-opts-given-and-not-start-unless-told-to + (let [passed-args (atom nil)] + (with-redefs [start-nrepl (fn [& args] (reset! passed-args args))] + (init-repl nil {:ring {:nrepl {:port 1 :start? false}}}) + (is (not @passed-args))))) + +(deftest immutant-opts-should-override-ring-opts + (let [passed-args (atom nil)] + (with-redefs [start-nrepl (fn [& args] (reset! passed-args args))] + (init-repl {:nrepl-port 2} {:ring {:nrepl {:port 1 :start? true}}}) + (is (= [nil 2] @passed-args))))) + +(deftest repl-should-not-start-when-ring-opts-are-present-but-start?-is-false + (let [started? (atom nil)] + (with-redefs [start-nrepl (fn [& _] (reset! started? true)) + u/dev-mode? (constantly true)] + (init-repl nil {:ring {:nrepl {:port 1 :start? false}}}) + (is (not @started?))))) + +(deftest repl-should-not-start-when-ring-opts-are-present-but-start?-is-missing + (let [started? (atom nil)] + (with-redefs [start-nrepl (fn [& _] (reset! started? true)) + u/dev-mode? (constantly true)] + (init-repl nil {:ring {:nrepl {:port 1}}}) + (is (not @started?))))) + +(deftest repl-should-not-start-when-ring-opts-are-present-but-nrepl-port-is-nil + (let [started? (atom nil)] + (with-redefs [start-nrepl (fn [& _] (reset! started? true)) + u/dev-mode? (constantly true)] + (init-repl {:nrepl-port nil} {:ring {:nrepl {:port 1 :start? true}}}) + (is (not @started?)))))) diff --git a/modules/core/src/test/clojure/immutant/runtime_test.clj b/modules/core/src/test/clojure/immutant/runtime_test.clj index 8497b4b0..4988eb95 100644 --- a/modules/core/src/test/clojure/immutant/runtime_test.clj +++ b/modules/core/src/test/clojure/immutant/runtime_test.clj @@ -21,6 +21,7 @@ immutant.test.helpers) (:require [immutant.registry :as registry] [immutant.dev :as dev] + [immutant.repl :as repl] [clojure.java.io :as io] [immutant.logging :as log] [dynapath.util :as dp])) @@ -79,12 +80,15 @@ (initialize "immutant.runtime-test/update-a-value") (is (= "biscuit" @a-value))) -(deftest initialize-with-no-init-fn-and-no-init-ns-should-do-nothing - (let [log-data (atom nil)] +(deftest initialize-with-no-init-fn-and-no-init-ns-should-only-init-repl + (let [log-data (atom nil) + repl (atom nil)] (with-redefs [log/log* (fn [_ _ msg] - (reset! log-data msg))] + (reset! log-data msg)) + repl/init-repl (fn [_ _] (reset! repl :started))] (initialize nil) - (is (re-find #"no initialization" @log-data))))) + (is (re-find #"no initialization" @log-data)) + (is (= :started @repl))))) (deftest initialize-from-lein-ring-options (add-url (io/resource "lein-ring-test/src/"))