deps phases 3-4: uberscript bundling + conformance harness

Phase 3 — bundling. `jolt uberscript OUT -m NS` requires NS, uses the loader's
recorded load order (a dep finishes loading before its requirer, so it's
topological) to concatenate the used namespaces into one .clj that runs on a
plain jolt with no deps/jpm. `jolt-deps uberscript` resolves first. The loader
records loaded file paths when ctx env has :loaded-files.

Phase 4 — conformance. deps-conformance-test resolves real pure-cljc git libs
and reports load/run status, gated behind JOLT_CONFORMANCE so CI stays offline.
First run: medley works; cuerdas hits a reader gap (filed); stuartsierra/
dependency uses Long/MAX_VALUE (JVM interop, out of scope).

Tests: uberscript-test, deps-conformance-test (skips without the flag).
This commit is contained in:
Yogthos 2026-06-05 23:36:40 -04:00
parent 6a1706df10
commit 30c4bb0dc2
7 changed files with 174 additions and 8 deletions

View file

@ -0,0 +1,51 @@
# `jolt uberscript` bundles a namespace and everything it requires into one .clj
# that runs on a plain jolt with no JOLT_PATH / deps. Runs from source.
(defn- run [env-jolt-path & args]
(if env-jolt-path (os/setenv "JOLT_PATH" env-jolt-path) (os/setenv "JOLT_PATH" nil))
(def p (os/spawn ["janet" "src/jolt/main.janet" ;args] :p {:out :pipe :err :pipe}))
(def out (:read (p :out) :all))
(os/proc-wait p)
(string (or out "")))
(defn- mkdirs [p]
(var acc nil)
(each seg (filter |(not= "" $) (string/split "/" p))
(set acc (if (nil? acc) (if (string/has-prefix? "/" p) (string "/" seg) seg) (string acc "/" seg)))
(unless (os/stat acc) (os/mkdir acc))))
(defn- rmrf [p]
(when (os/stat p)
(if (= :directory (os/stat p :mode))
(do (each e (os/dir p) (rmrf (string p "/" e))) (os/rmdir p))
(os/rm p))))
(def base (string (or (os/getenv "TMPDIR") "/tmp") "/jolt-uber-" (os/time)))
(rmrf base)
(mkdirs (string base "/proj/src/app"))
(mkdirs (string base "/lib/src/greet"))
(spit (string base "/lib/src/greet/core.clj")
"(ns greet.core)\n(defn hello [n] (str \"Hello, \" n \"!\"))\n")
(spit (string base "/proj/src/app/core.clj")
"(ns app.core (:require [greet.core :as g]))\n(defn -main [& args] (println (g/hello (or (first args) \"world\"))))\n")
(var fails 0)
(defn check [label got pred]
(if (pred got) (print " ok " label)
(do (++ fails) (printf " FAIL %s: got %q" label got))))
(defn- has [s] (fn [x] (string/find s x)))
(def roots (string base "/proj/src:" base "/lib/src"))
(def out (string base "/out.clj"))
# build the uberscript with the dep roots on JOLT_PATH
(run roots "uberscript" out "-m" "app.core")
(check "uberscript written" (if (os/stat out) "yes" "no") (has "yes"))
(check "bundles the dep ns" (slurp out) (has "(ns greet.core)"))
# run it standalone: no JOLT_PATH, so it only works if the dep was inlined
(check "runs standalone" (run nil out "Bob") (has "Hello, Bob!"))
(rmrf base)
(if (> fails 0)
(error (string "uberscript-test: " fails " failing check(s)"))
(print "\nAll uberscript tests passed!"))