Skip to content

Commit

Permalink
Make hot-reloading of deps.edn also watch associated projects
Browse files Browse the repository at this point in the history
When working on multiple related code bases linked via `:local/root`, this
option can be used to track changes to `deps.edn` in all of them.
  • Loading branch information
plexus committed Aug 25, 2022
1 parent fc85b1d commit fd51db4
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 147 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

## Added

- Support watching multiple `deps.edn` files referenced via `:local/root`

## Fixed

## Changed
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ versions, and add them to the classpath.
Caveat: we can only *add* to the classpath, any dependencies that were present
when the app started will remain accessible.

You can pass the option `:include-local-roots? true` to also watch any
`deps.edn` of projects that are referenced via `:local/root` in your project's
`deps.edn`

### Classpath inspection and manipulation

```clojure
Expand Down
2 changes: 1 addition & 1 deletion bb.edn
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{:deps
{lambdaisland/open-source {:git/url "https://github.com/lambdaisland/open-source"
:sha "a4487e78df935b6d8775019d95292fe4f375bdb7"
:sha "7f39ffb76d47e2ff83d4478957c2ca4fd180f3e5"
#_#_:local/root "../open-source"}}}
125 changes: 0 additions & 125 deletions bin/bb

This file was deleted.

2 changes: 1 addition & 1 deletion bin/proj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!bin/bb
#!/usr/bin/env bb

(ns proj
(:require [lioss.main :as lioss]))
Expand Down
4 changes: 2 additions & 2 deletions deps.edn
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{:paths ["src" "resources"]

:deps
{rewrite-clj/rewrite-clj {:mvn/version "1.0.682-alpha"}
org.clojure/tools.deps.alpha {:mvn/version "0.12.1030"}
{rewrite-clj/rewrite-clj {:mvn/version "1.1.45"}
org.clojure/tools.deps.alpha {:mvn/version "0.14.1222"}
com.lambdaisland/shellutils {:mvn/version "0.0.10"}
org.clojure/java.classpath {:mvn/version "1.0.0"}
com.nextjournal/beholder {:mvn/version "1.0.0"}}}
71 changes: 53 additions & 18 deletions src/lambdaisland/classpath/watch_deps.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,45 @@
"Watch deps.edn for changes"
(:require [clojure.java.classpath :as cp]
[clojure.string :as str]
[clojure.java.io :as io]
[clojure.tools.deps.alpha :as deps]
[lambdaisland.classpath :as licp]
[nextjournal.beholder :as beholder]))
[nextjournal.beholder :as beholder])
(:import java.util.regex.Pattern
java.nio.file.LinkOption
java.nio.file.Paths))

(def watcher (atom nil))

(defn- on-event [opts {:keys [type path]}]
(when (and (= :modify type)
;; On Mac the path will be absolute and include the watched dir,
;; e.g. `/Users/x/project/./deps.edn`
;; On other systems it seems to be relative, like `./deps.edn`
(str/ends-with? (str path) "./deps.edn"))
(println "✨ Reloading deps.edn ✨")
(let [new-paths (remove (set (map str (cp/system-classpath)))
(:classpath-roots (deps/create-basis opts)))]
(doseq [path new-paths]
(println "- " path))
(licp/install-priority-loader! new-paths))))
(defn canonical-path [p]
(.toRealPath (Paths/get p (into-array String [])) (into-array LinkOption [])))

(def process-root-path (canonical-path "."))

(defn- on-event [deps-path opts {:keys [type path]}]
(locking watcher
(when (and (= :modify type)
;; Before we used "." as the watch path, resulting in a
;; difference between mac, where the path would look like this
;; `/Users/x/project/./deps.edn`, vs Linux where the path would
;; look like this `./deps.edn`.
;;
;; We now turn `"."` into a canonical path before starting the
;; watcher, which means we get fully qualified filenames for both
;; in this equality check.
(= path deps-path))
(try
(println "✨ Reloading"
(str (.relativize process-root-path path))
"")
(let [added-paths (remove (set (map str (cp/system-classpath)))
(:classpath-roots (deps/create-basis opts)))]
(doseq [path added-paths]
(println "+" (str/replace path #"^.*/\.m2/repository/" "")))
(licp/install-priority-loader! added-paths))
(catch Exception e
(println "Error while reloading deps.edn")
(println e))))))

(defn start!
"Start a file system watcher to pick up changes in `deps.edn'
Expand All @@ -35,9 +56,20 @@
(swap! watcher
(fn [w]
(when w
(println "Stopping existing `deps.edn' watcher")
(beholder/stop w))
(beholder/watch (partial on-event opts) "."))))
(println "Stopping existing `deps.edn' watchers")
(run! beholder/stop w))
(let [basis (deps/create-basis opts)
roots (cons (str process-root-path)
(when (:include-local-roots? opts)
(->> (vals (:libs basis))
(keep :local/root)
(map canonical-path)
(map str))))]
(doall
(for [root roots]
(beholder/watch
(partial #'on-event (Paths/get root (into-array String ["deps.edn"])) opts)
root)))))))

(defn stop!
"Stop a previously started watcher"
Expand All @@ -48,6 +80,9 @@
(beholder/stop w))
nil)))


(comment
(start! {:aliases [:dev]}))
(start! {:aliases [:dev]})

(deps/create-basis {:aliases [:backend]
:extra '{cider/cider-nrepl #:mvn{:version "0.28.5"}
refactor-nrepl/refactor-nrepl #:mvn{:version "3.5.2"}}}))

0 comments on commit fd51db4

Please sign in to comment.