Skip to content

Commit

Permalink
Add support for lein checkouts
Browse files Browse the repository at this point in the history
- Add checkouts source directories to the classpath
- Add checkouts source directories to :source-paths

Fixes #9
  • Loading branch information
danielcompton committed Dec 17, 2017
1 parent 8f936b6 commit 013ba71
Show file tree
Hide file tree
Showing 14 changed files with 205 additions and 23 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,16 @@ a great deal of programming complexity stems from complex interactions
(side effecting events) between things that have local state, it is my
belief that reloadable code is often simply better code.

## Checkouts

Figwheel supports Leiningen's [checkouts][checkouts]
mechanism. This is useful when you want to make changes to a library
while you are developing an application that is using that library.
Figwheel will automatically pick up the :source-paths of any projects
symlinked in the `checkouts` directory. For full details, see
Leiningen's documentation on [checkouts][checkouts].

[checkouts]: (https://github.com/technomancy/leiningen/blob/master/doc/TUTORIAL.md#checkout-dependencies)

## More React Advocacy

Expand Down
1 change: 1 addition & 0 deletions plugin/project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

:profiles {:dev {:dependencies [[leiningen "2.7.1"]
[org.clojure/test.check "0.9.0"]]
:resource-paths ["test-resources"]
:source-paths ["dev" "src"]
:aliases {"change-version" ["run" "-m" "figwheel-tasks.core" ":change-version"]
"install-all" ["run" "-m" "figwheel-tasks.core" ":install-all"]}}}
Expand Down
71 changes: 58 additions & 13 deletions plugin/src/leiningen/figwheel.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
(:require
#_[clojure.pprint :as pp]
[leiningen.core.eval :as leval]
[leiningen.core.project :as lproject]
[leiningen.clean :as clean]
[leiningen.core.main :as main]
[clojure.java.io :as io]
[clojure.set :refer [intersection]]
[leiningen.figwheel.fuzzy :as fuz]
[simple-lein-profile-merge.core :as lm]))
[simple-lein-profile-merge.core :as lm])
(:import (java.io File)
(java.nio.file Path)))

(def _figwheel-version_ "0.5.15-SNAPSHOT")

Expand Down Expand Up @@ -284,6 +287,44 @@
(when (every? not-empty args)
(not-empty (apply intersection (map set args)))))

(defn checkout-source-paths
"Get source paths for all of the lein projects in the checkouts directory."
[project]
(let [checkout-project-maps (lproject/read-checkouts project)
checkout-sources (for [co-project checkout-project-maps
source-path (:source-paths co-project)]
;; Make the checkout source path pretty, e.g. checkouts/utils-lib/src
(str (.relativize (.toPath (io/file (:root project))) ;; Note, root of the parent project, not the checkout project
(.toPath (io/file source-path)))))]
(distinct checkout-sources)))

(defn map-vals
"Returns a hashmap consisting of the result of applying f to
the value of each set in hashmap.
Function f should accept one single argument."
[f m]
(persistent!
(reduce-kv (fn [m k v] (assoc! m k (f v)))
(transient (empty m)) m)))

(defn update-builds
"Map a function across each cljsbuild build config.
The :cljsbuild :builds path can either be a vector of builds,
or a map of build-ids to builds. This function handles both variants."
[project f]
(if-let [builds (get-in project [:cljsbuild :builds])]
(assoc-in project
[:cljsbuild :builds]
(if (map? builds)
(map-vals f builds)
(map f builds)))
project))

(defn add-source-paths [project source-paths]
(update-builds project
(fn [build] (update build :source-paths (fn [existing-paths] (reduce conj existing-paths source-paths))))))

(defn source-paths-for-classpath [{:keys [figwheel-options all-builds build-ids] :as data}]
(if-not (and all-builds (not-empty all-builds))
[]
Expand Down Expand Up @@ -398,21 +439,25 @@

(defn build-once [project build-ids]
(when-not (report-if-bad-build-ids project build-ids)
(run-build-once
project
(fuzzy-config-from-project project)
(source-paths-for-classpath
(normalize-data project build-ids))
(vec build-ids))))
(let [checkout-sources (checkout-source-paths project)
project (add-source-paths project checkout-sources)]
(run-build-once
project
(fuzzy-config-from-project project)
(source-paths-for-classpath
(normalize-data project build-ids))
(vec build-ids)))))

(defn figwheel-main [project build-ids]
(when-not (report-if-bad-build-ids project build-ids)
(run-figwheel
project
(fuzzy-config-from-project project)
(source-paths-for-classpath
(normalize-data project build-ids))
(vec build-ids))))
(let [checkout-sources (checkout-source-paths project)
project (add-source-paths project checkout-sources)]
(run-figwheel
project
(-> project fuzzy-config-from-project)
(source-paths-for-classpath
(normalize-data project build-ids))
(vec build-ids)))))

(defmulti fig-dispatch (fn [command _ _] command))

Expand Down
1 change: 1 addition & 0 deletions plugin/test-resources/test-project-no-checkouts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target/
11 changes: 11 additions & 0 deletions plugin/test-resources/test-project-no-checkouts/project.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
(defproject test-project-no-checkouts "1.0.0"
:description "A test project for testing Figwheel when there are no checkouts."
:dependencies [[org.clojure/clojure "1.9.0-alpha15"]
[org.clojure/clojurescript "1.9.908"]]
:source-paths ["src"]
:cljsbuild {:builds {:dev {:source-paths ["src"]
:compiler {:main core
:asset-path "js/out"
:output-to "resources/public/js/example.js"
:output-dir "resources/public/js/out"
:optimizations :none}}}})
3 changes: 3 additions & 0 deletions plugin/test-resources/test-project-no-checkouts/src/core.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(ns core)

;; Intentionally left blank
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target/
11 changes: 11 additions & 0 deletions plugin/test-resources/test-project-with-checkouts/project.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
(defproject test-project-with-checkouts "1.0.0"
:description "A test project for testing Figwheel with checkouts."
:dependencies [[org.clojure/clojure "1.9.0-alpha15"]
[org.clojure/clojurescript "1.9.908"]]
:source-paths ["src"]
:cljsbuild {:builds {:dev {:source-paths ["src"]
:compiler {:main core
:asset-path "js/out"
:output-to "resources/public/js/example.js"
:output-dir "resources/public/js/out"
:optimizations :none}}}})
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(ns core)

;; Intentionally left blank
1 change: 1 addition & 0 deletions plugin/test-resources/utils-lib/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target/
11 changes: 11 additions & 0 deletions plugin/test-resources/utils-lib/project.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
(defproject utils-lib "1.0.0"
:description "A test project to be consumed as a checkouts project."
:dependencies [[org.clojure/clojure "1.9.0-alpha15"]
[org.clojure/clojurescript "1.9.908"]]
:source-paths ["src"]
:cljsbuild {:builds {:dev {:source-paths ["src"]
:compiler {:main utils
:asset-path "js/out"
:output-to "resources/public/js/example.js"
:output-dir "resources/public/js/out"
:optimizations :none}}}})
3 changes: 3 additions & 0 deletions plugin/test-resources/utils-lib/src/utils.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(ns utils)

;; Intentionally left blank
100 changes: 90 additions & 10 deletions plugin/test/leiningen/figwheel_test.clj
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
(ns leiningen.figwheel-test
(:require
[leiningen.figwheel :as f]
[clojure.test :as t :refer [deftest is testing run-tests]]
[clojure.test.check :as tc]
[clojure.test.check.generators :as gen]
[clojure.test.check.properties :as prop]
[clojure.test.check.clojure-test :refer [defspec]]))
[leiningen.figwheel :as f]
[clojure.test :as t :refer [deftest is testing run-tests]]
[clojure.test.check :as tc]
[clojure.test.check.generators :as gen]
[clojure.test.check.properties :as prop]
[clojure.test.check.clojure-test :refer [defspec]]
[clojure.java.io :as io]))

(def iterations 10)

Expand Down Expand Up @@ -132,7 +133,86 @@
(gen/vector (gen/map (gen/return :source-paths)
(gen/vector gen/string)))))





(deftest update-builds-test
(testing "vector of builds"
(is (= (f/update-builds {:cljsbuild {:builds [{:id "dev"}
{:id "prod"}
{:id "test"}]}}
(fn [build]
(update build :source-paths conj "src")))
{:cljsbuild {:builds [{:id "dev"
:source-paths ["src"]}
{:id "prod"
:source-paths ["src"]}
{:id "test"
:source-paths ["src"]}]}})))
(testing "map of builds"
(is (= (f/update-builds {:cljsbuild {:builds {"dev" {}
"prod" {}
"test" {}}}}
(fn [build]
(update build :source-paths conj "src")))
{:cljsbuild {:builds {"dev" {:source-paths ["src"]}
"prod" {:source-paths ["src"]}
"test" {:source-paths ["src"]}}}})))
(testing "edge cases around no builds"
(testing "vector of builds"
(is (= (f/update-builds {:cljsbuild {:builds []}}
(fn [x]
1))
{:cljsbuild {:builds []}}))
(is (= (f/update-builds {:cljsbuild {}}
(fn [x]
1))
{:cljsbuild {}})))
(testing "map of builds"
(is (= (f/update-builds {:cljsbuild {:builds {}}}
(fn [x]
1))
{:cljsbuild {:builds {}}}))
(is (= (f/update-builds {:cljsbuild {}}
(fn [x]
1))
{:cljsbuild {}})))))

(deftest add-source-paths-test
(testing "vector of builds"
(is (= (f/add-source-paths
{:cljsbuild {:builds [{:id "dev"
:source-paths ["src/cljs" "src/cljc" "dev"]
:resource-paths ["resources"]}
{:id "prod"
:source-paths ["src/cljs" "src/cljc" "prod"]
:resource-paths ["resources"]}]}}
["checkouts/util-lib/src"])
{:cljsbuild {:builds [{:id "dev"
:source-paths ["src/cljs" "src/cljc" "dev" "checkouts/util-lib/src"]
:resource-paths ["resources"]}
{:id "prod"
:source-paths ["src/cljs" "src/cljc" "prod" "checkouts/util-lib/src"]
:resource-paths ["resources"]}]}}))))

(deftest checkout-source-paths-test
(let [cwd (.getCanonicalFile (io/file "."))]
(testing "test project with checkouts"
(is (= (f/checkout-source-paths
{:root (str cwd "/test-resources/test-project-with-checkouts")
:source-paths ["src"]
:cljsbuild {:builds {:dev {:source-paths ["src"]
:compiler {:main 'core
:asset-path "js/out"
:output-to "resources/public/js/example.js"
:output-dir "resources/public/js/out"
:optimizations :none}}}}})
["checkouts/utils-lib/src"])))
(testing "test project with no checkouts"
(is (= (f/checkout-source-paths
{:root (str cwd "/test-resources/test-project-with-no-checkouts")
:source-paths ["src"]
:cljsbuild {:builds {:dev {:source-paths ["src"]
:compiler {:main 'core
:asset-path "js/out"
:output-to "resources/public/js/example.js"
:output-dir "resources/public/js/out"
:optimizations :none}}}}})
[])))))

0 comments on commit 013ba71

Please sign in to comment.