Skip to content

Commit

Permalink
Merge pull request #182 from connor-kilgore/master
Browse files Browse the repository at this point in the history
New freshener library, and src files retain save state data.
  • Loading branch information
slagyr authored Sep 12, 2024
2 parents d6b5c2c + e0c375f commit c57575e
Show file tree
Hide file tree
Showing 15 changed files with 185 additions and 57 deletions.
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 3.4.9

* migrates from deprecated make-fresh library to clojure.tools.namespace
* fixes bug where changes to src files in a directory that includes a space char does not register updates to the vigilant runner

# 3.4.8

* can now be built and executed under `:advanced` ClojureScript optimizations
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ Include speclj in your `:dev` profile `:dependencies` and`:plugins`. Then change
```clojure
; - snip
:dependencies [[org.clojure/clojure "1.11.3"]]
:profiles {:dev {:dependencies [[speclj "3.4.8"]]}}
:plugins [[speclj "3.4.8"]]
:profiles {:dev {:dependencies [[speclj "3.4.9"]]}}
:plugins [[speclj "3.4.9"]]
:test-paths ["spec"]
```

Expand Down Expand Up @@ -140,7 +140,7 @@ Add a `spec` alias to your `deps.edn`.
```clojure
{
:aliases {:spec {:main-opts ["-m" "speclj.main" "-c"]
:extra-deps {speclj/speclj {:mvn/version "3.4.8"}}
:extra-deps {speclj/speclj {:mvn/version "3.4.9"}}
:extra-paths ["spec"]}}
}
```
Expand Down Expand Up @@ -312,7 +312,7 @@ Here's an example alias for your `deps.edn`.
```clojure
{:aliases {:cov {:main-opts ["-m" "cloverage.coverage" "--runner" ":speclj" "-p" "src" "-s" "spec" ]
:extra-deps {cloverage/cloverage {:mvn/version "1.2.4"}
speclj/speclj {:mvn/version "3.4.8"}}}}}
speclj/speclj {:mvn/version "3.4.9"}}}}}
```

Sadly, Cloverage doesn't offer a way to pass arguments to the runner (Speclj in this case). Speclj will use the
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.4.8
3.4.9
2 changes: 1 addition & 1 deletion deps.edn
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
:paths ["src"]
:deps {
fresh/fresh {:mvn/version "1.1.2"}
mmargs/mmargs {:mvn/version "1.2.0"}
org.clojure/clojure {:mvn/version "1.11.3"}
trptcolin/versioneer {:mvn/version "0.1.1"}
org.clojure/tools.namespace {:mvn/version "1.5.0"}
}
:aliases {
:test {:extra-deps {
Expand Down
1 change: 1 addition & 0 deletions examples/sample/a.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
I'm a clojure file
1 change: 1 addition & 0 deletions examples/sample/b.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
I'm a clojure common file
1 change: 1 addition & 0 deletions examples/sample/c.cljx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
I'm neither
1 change: 1 addition & 0 deletions examples/sample/portable.cljx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
I'm antiquated
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"dependencies": {
"puppeteer": "^13.5.1"
"puppeteer": "^22.12.1"
}
}
54 changes: 54 additions & 0 deletions spec/speclj/freshener_spec.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
(ns speclj.freshener-spec
(:require [speclj.core :refer :all]
[speclj.freshener :refer :all]
[clojure.tools.namespace.repl :as repl]
[clojure.tools.namespace.dir :as dir])
(:use [clojure.java.io :only (file copy make-input-stream delete-file make-parents)]))

(def sample-dir (.getCanonicalFile (file "examples/sample")))

(defn sample-file [dir name]
(file dir name))

(defn write-file [dir name content]
(let [file (sample-file dir name)]
(make-parents file)
(copy (make-input-stream (.getBytes content) {}) file)
file))

(defn tweak-mod-time [file tweak]
(let [mod-time (+ (.lastModified file) (* 1000 tweak))]
(.setLastModified file mod-time)))

(describe "Freshener"

(it "finds specified files by default"
(write-file sample-dir "portable.cljx" "I'm antiquated")
(let [files (find-files-in #".*\.cljx" sample-dir)]
(should-contain "portable.cljx" (set (map #(.getName %) files)))))

(it "first freshening adds files to listing"
(write-file sample-dir "a.clj" "I'm a clojure file")
(write-file sample-dir "b.cljc" "I'm a clojure common file")
(write-file sample-dir "c.cljx" "I'm neither")
(let [files (clj-files-in sample-dir)]
(should-contain "a.clj" (set (map #(.getName %) files)))
(should-contain "b.cljc" (set (map #(.getName %) files)))
(should-not-contain "c.cljx" (set (map #(.getName %) files)))))

(context "freshen"
(before
(repl/set-refresh-dirs sample-dir))

(it "new files are detected and added to tracker"
(repl/clear)
(freshen)
(should= 2 (count (::dir/files repl/refresh-tracker)))
(should-contain "a.clj" (set (map #(.getName %) (::dir/files repl/refresh-tracker))))
(should-contain "b.cljc" (set (map #(.getName %) (::dir/files repl/refresh-tracker)))))

(it "refresh dirs are updated to nil indicating the classpath"
(freshen)
(should= nil repl/refresh-dirs)))

(repl/clear))
2 changes: 1 addition & 1 deletion src/speclj/config.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,4 @@
*omit-pending?* (:omit-pending config)
*full-stack-trace?* (some? (:stacktrace config))
*tag-filter* (parse-tags (:tags config))]
(action)))
(action)))
56 changes: 56 additions & 0 deletions src/speclj/freshener.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
(ns speclj.freshener
(:require
[clojure.tools.namespace.dir :as dir]
[clojure.tools.namespace.file :as file]
[clojure.tools.namespace.reload :as reload]
[clojure.tools.namespace.repl :as repl]
[clojure.tools.namespace.track :as track]
[speclj.config]
[speclj.reporting])
(:use
[clojure.java.io :only [file]]))

(defn find-files-in
"Returns a seq of all files (matching the regex) contained in the given directories."
[pattern & dirs]
(let [dirs (map #(.getCanonicalFile %) dirs)
files (reduce #(into %1 (file-seq (file %2))) [] dirs)
files (remove #(.isHidden %) files)
clj-files (filter #(re-matches pattern (.getName %)) files)]
clj-files))

(def clj-file-regex #".*\.clj(c)?")
(defn clj-files-in
"Returns a seq of all clojure source files contained in the given directories."
[& dirs] (apply find-files-in clj-file-regex dirs))

(defn remove-value [val coll]
(remove #(= % val) coll))

(defn remove-ignore [tracker namespace]
(when-let [file (first (some #(when (= (val %) namespace) %) (::file/filemap tracker)))]
(alter-var-root #'repl/refresh-tracker
(constantly
(assoc tracker
::track/load (remove-value namespace (::track/load tracker))
::track/unload (remove-value namespace (::track/unload tracker))
::file/filemap (dissoc (::file/filemap tracker) file)
::dir/files (set (remove-value file (::dir/files tracker))))))))

(defn find-key-by-value [m val]
(some (fn [[k v]] (when (= v val) k)) m))

(def ignored-namespaces ['speclj.config 'speclj.run.vigilant
'speclj.results 'speclj.core
'speclj.reporting 'speclj.running])

(defn freshen []
(repl/scan)
(doseq [namespace ignored-namespaces]
(remove-ignore repl/refresh-tracker namespace))
(let [reloaded-files
(for [ns (::track/load repl/refresh-tracker)]
(find-key-by-value (::file/filemap repl/refresh-tracker) ns))]
(alter-var-root #'repl/refresh-tracker reload/track-reload)
(repl/set-refresh-dirs)
reloaded-files))
2 changes: 1 addition & 1 deletion src/speclj/run/standard.cljc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(ns speclj.run.standard
(:require #?(:clj [clojure.java.io :as io])
#?(:clj [fresh.core :as fresh])
#?(:clj [speclj.freshener :as fresh])
#?(:cljs [speclj.report.progress])
#?(:cljs [speclj.components :as components])
[speclj.config :as config]
Expand Down
76 changes: 43 additions & 33 deletions src/speclj/run/vigilant.clj
Original file line number Diff line number Diff line change
@@ -1,57 +1,66 @@
(ns speclj.run.vigilant
(:require [clojure.java.io :as io]
[fresh.core :refer [clj-files-in make-fresh ns-to-file]]
[clojure.tools.namespace.reload :as reload]
[clojure.tools.namespace.repl :as repl]
[clojure.tools.namespace.dir :as dir]
[clojure.tools.namespace.file :as file]
[clojure.tools.namespace.track :as track]
[speclj.config :as config]
[speclj.platform :refer [current-time endl enter-pressed? format-seconds secs-since]]
[speclj.freshener :refer [freshen]]
[speclj.platform :refer [current-time enter-pressed? endl format-seconds secs-since]]
[speclj.reporting :as reporting]
[speclj.results :as results]
[speclj.running :as running])
(:import (java.util.concurrent ScheduledThreadPoolExecutor TimeUnit)))

(def start-time (atom 0))
(def current-error-data (atom nil))

(defn- ns-for-results [results]
(set (map #(str (.ns @(.. % characteristic parent))) results)))
(defn get-error-data [e]
(:data (first (:via (Throwable->map e)))))

(defn- report-update [report]
(let [reporters (config/active-reporters)
reloads (:reloaded report)]
(when (seq reloads)
(defn- report-update [files start-time]
(let [reporters (config/active-reporters)]
(when (seq files)
(reporting/report-message* reporters (str endl "----- " (str (java.util.Date.) " -----")))
(reporting/report-message* reporters (str "took " (format-seconds (secs-since @start-time)) " to determine file statuses."))
(reporting/report-message* reporters (str "took " (format-seconds (secs-since start-time)) " to determine file statuses."))
(reporting/report-message* reporters "reloading files:")
(doseq [file reloads] (reporting/report-message* reporters (str " " (.getCanonicalPath file))))))
(doseq [file files]
(do
(reporting/report-message* reporters (str " " (.getCanonicalPath file))))
)))
true)

(defn- reload-files [runner current-results]
(let [previous-failed-files (map ns-to-file (ns-for-results @(.previous-failed runner)))
files-to-reload (set (concat previous-failed-files current-results))]
(swap! (.file-listing runner) #(apply dissoc % previous-failed-files))
(make-fresh (.file-listing runner) files-to-reload report-update)))

(defn- reload-report [runner report]
(let [reloads (:reloaded report)]
(when (seq reloads)
(reload-files runner reloads)))
false)

(defn- tick [configuration]
(with-bindings configuration
(let [runner (config/active-runner)
reporters (config/active-reporters)]
(let [runner (config/active-runner)
reporters (config/active-reporters)
reloaded-files (freshen)]
(try
(reset! start-time (current-time))
(make-fresh (.file-listing runner) (set (apply clj-files-in @(.directories runner))) (partial reload-report runner))
(when (seq @(.descriptions runner))
(reset! (.previous-failed runner) (:fail (results/categorize (seq @(.results runner)))))
(running/run-and-report runner reporters))
(cond
(::reload/error repl/refresh-tracker)
(throw (::reload/error repl/refresh-tracker))
(seq @(.descriptions runner))
(do
(report-update reloaded-files @start-time)
(reset! current-error-data nil)
(reset! (.previous-failed runner) (:fail (results/categorize (seq @(.results runner)))))
(running/run-and-report runner reporters)))
(catch java.lang.Throwable e
(running/process-compile-error runner e)
(reporting/report-runs* reporters @(.results runner))))
(let [error-data (get-error-data e)]
(alter-var-root #'repl/refresh-tracker
(constantly (assoc repl/refresh-tracker ::track/load [])))
(running/process-compile-error runner e)
(reporting/report-runs* reporters @(.results runner))
(reset! current-error-data error-data))))
(reset! (.descriptions runner) [])
(reset! (.results runner) []))))

(defn- reset-runner [runner]
(reset! current-error-data nil)
(repl/clear)
(apply repl/set-refresh-dirs @(.directories runner))
(reset! (.previous-failed runner) [])
(reset! (.results runner) [])
(reset! (.file-listing runner) {}))
Expand All @@ -64,11 +73,12 @@
(deftype VigilantRunner [file-listing results previous-failed directories descriptions]
running/Runner
(run-directories [this directories _reporters]
(let [scheduler (ScheduledThreadPoolExecutor. 1)
(let [scheduler (ScheduledThreadPoolExecutor. 1)
configuration (config/config-bindings)
runnable (fn [] (tick configuration))
dir-files (map io/file directories)]
runnable (fn [] (tick configuration))
dir-files (map io/file directories)]
(reset! (.directories this) dir-files)
(apply repl/set-refresh-dirs dir-files)
(.scheduleWithFixedDelay scheduler runnable 0 500 TimeUnit/MILLISECONDS)
(.scheduleWithFixedDelay scheduler (fn [] (listen-for-rerun configuration)) 0 500 TimeUnit/MILLISECONDS)
(.awaitTermination scheduler Long/MAX_VALUE TimeUnit/SECONDS)
Expand Down
29 changes: 14 additions & 15 deletions src/speclj/running.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -100,20 +100,20 @@

(defn- report-result [result-constructor characteristic start-time reporters failure]
(let [present-args (filter identity [characteristic (secs-since start-time) failure])
result (apply result-constructor present-args)]
result (apply result-constructor present-args)]
(report-run result reporters)
result))

(defn- do-characteristic [characteristic reporters]
(let [description @(.-parent characteristic)
befores (collect-components #(deref (.-befores %)) description)
afters (collect-components #(deref (.-afters %)) description)
core-body (.-body characteristic)
(let [description @(.-parent characteristic)
befores (collect-components #(deref (.-befores %)) description)
afters (collect-components #(deref (.-afters %)) description)
core-body (.-body characteristic)
before-and-after-body (fn [] (eval-characteristic befores core-body afters))
arounds (collect-components #(deref (.-arounds %)) description)
full-body (nested-fns before-and-after-body (map #(.-body %) arounds))
withs (collect-components #(deref (.-withs %)) description)
start-time (current-time)]
arounds (collect-components #(deref (.-arounds %)) description)
full-body (nested-fns before-and-after-body (map #(.-body %) arounds))
withs (collect-components #(deref (.-withs %)) description)
start-time (current-time)]
(try
(do
(full-body)
Expand All @@ -123,7 +123,7 @@
(report-result pending-result characteristic start-time reporters e)
(report-result fail-result characteristic start-time reporters e)))
(finally
(reset-withs withs))))) ;MDM - Possible clojure bug. Inlining reset-withs results in compile error
(reset-withs withs))))) ;MDM - Possible clojure bug. Inlining reset-withs results in compile error

(defn- do-characteristics [characteristics reporters]
(doall
Expand All @@ -133,7 +133,7 @@
(declare do-description)

(defn- do-child-contexts [context results reporters]
(loop [results results
(loop [results results
children @(.-children context)]
(if (seq children)
(recur (concat results (do-description (first children) reporters)) (rest children))
Expand All @@ -148,9 +148,9 @@

#?(:clj
(defn- with-withs-bound [description body]
(let [withs (concat @(.-withs description) @(.-with-alls description))
ns (the-ns (symbol (.-ns description)))
with-mappings (reduce #(assoc %1 (ns-resolve ns (.-name %2)) %2) {} withs)
(let [withs (concat @(.-withs description) @(.-with-alls description))
ns (the-ns (symbol (.-ns description)))
with-mappings (reduce #(assoc %1 (ns-resolve ns (.-name %2)) %2) {} withs)
with-and-ns-mappings (assoc with-mappings #'*ns* ns)]
(with-bindings* with-and-ns-mappings body)))

Expand Down Expand Up @@ -187,7 +187,6 @@

(finally
(reset-withs @(.-with-alls description))))))))))

(defn process-compile-error [runner e]
(let [error-result (error-result e)]
(swap! (.-results runner) conj error-result)
Expand Down

0 comments on commit c57575e

Please sign in to comment.