Inject an addon that was NOT on the classpath when the host booted.
inject! is the mount pipeline run over a slice that did not exist yet:
put the addon's paths on the live classpath, discover the manifests under
them (and ONLY under them — an addon already on the classpath that the
composer chose not to mount must not be resurrected by a scan), solve the
new specs against the peers already mounted, tear down the mounted
dependents that now have a new sibling to receive, mount the slice through
the ordinary IMountDriver, and register the new addons with hive-hot so
they reload like the rest.
Classpath extension is a JVM concern: the URL is added to the highest
DynamicClassLoader above the calling thread's context loader, which is the
loader every later require resolves through in an nREPL-hosted image. A
thread with no DynamicClassLoader in its chain cannot extend the classpath;
inject! then REFUSES with :hot/no-dynamic-classloader rather than mounting
code the next require would fail to find.
Maven dependencies of the injected addon are NOT resolved by default; pass
:resolve-deps? true to hand the project's deps.edn :deps to
clojure.repl.deps/add-libs first (needs a tools.deps basis in the image).
Inject an addon that was NOT on the classpath when the host booted. `inject!` is the mount pipeline run over a slice that did not exist yet: put the addon's paths on the live classpath, discover the manifests under them (and ONLY under them — an addon already on the classpath that the composer chose not to mount must not be resurrected by a scan), solve the new specs against the peers already mounted, tear down the mounted dependents that now have a new sibling to receive, mount the slice through the ordinary IMountDriver, and register the new addons with hive-hot so they reload like the rest. Classpath extension is a JVM concern: the URL is added to the highest DynamicClassLoader above the calling thread's context loader, which is the loader every later `require` resolves through in an nREPL-hosted image. A thread with no DynamicClassLoader in its chain cannot extend the classpath; inject! then REFUSES with :hot/no-dynamic-classloader rather than mounting code the next require would fail to find. Maven dependencies of the injected addon are NOT resolved by default; pass `:resolve-deps? true` to hand the project's deps.edn :deps to clojure.repl.deps/add-libs first (needs a tools.deps basis in the image).
(dynamic-loader)The highest DynamicClassLoader in the calling thread's loader chain — the context loader's chain first, then clojure.lang.RT/baseLoader's — or nil when there is none.
The highest DynamicClassLoader in the calling thread's loader chain — the context loader's chain first, then clojure.lang.RT/baseLoader's — or nil when there is none.
(extend-classpath! path)(extend-classpath! path {:keys [loader]})Put path (a directory or a jar) on the live classpath. Idempotent: a URL
the loader chain already carries is reported :already? true and not
re-added.
(r/ok {:url .. :already? bool :loader <loader>}) on success; (r/err :hot/path-absent ..) when the path does not exist; (r/err :hot/no-dynamic-classloader ..) when no loader can be extended.
Put `path` (a directory or a jar) on the live classpath. Idempotent: a URL
the loader chain already carries is reported :already? true and not
re-added.
(r/ok {:url .. :already? bool :loader <loader>}) on success;
(r/err :hot/path-absent ..) when the path does not exist;
(r/err :hot/no-dynamic-classloader ..) when no loader can be extended.(inject! host specs path & [opts])Mount the addons whose manifests live under path into the running host,
alongside specs — the MountSpecs already mounted (the reload bridge's
effective specs), which is what the new ones are solved against and what
decides which dependents get remounted.
path is a project dir (its deps.edn :paths are the entries), a plain
source dir, or a jar.
opts: {:mount-opts forwarded to mount! (e.g. :resolve-config); the keys in hive-addon.hot/mount-opt-keys are folded in from the top level as well :solve-opts forwarded to solve (:rules) :mount-driver IMountDriver override :loader DynamicClassLoader override :resolve-deps? hand the project's :deps to add-libs first :hot? register the new addons with hive-hot (default true)}
Returns an InjectReport. Never throws; every failure is in the report.
Mount the addons whose manifests live under `path` into the running `host`,
alongside `specs` — the MountSpecs already mounted (the reload bridge's
effective specs), which is what the new ones are solved against and what
decides which dependents get remounted.
`path` is a project dir (its deps.edn :paths are the entries), a plain
source dir, or a jar.
opts: {:mount-opts forwarded to mount! (e.g. :resolve-config); the keys
in hive-addon.hot/mount-opt-keys are folded in from
the top level as well
:solve-opts forwarded to solve (:rules)
:mount-driver IMountDriver override
:loader DynamicClassLoader override
:resolve-deps? hand the project's :deps to add-libs first
:hot? register the new addons with hive-hot (default true)}
Returns an InjectReport. Never throws; every failure is in the report.(manifests-under paths)MountSpecs whose manifest lives under paths — discovered through a
throwaway URLClassLoader over exactly those entries and no parent, so
nothing else on the classpath is seen. Returns {:specs [..] :errors [..]}.
MountSpecs whose manifest lives under `paths` — discovered through a
throwaway URLClassLoader over exactly those entries and no parent, so
nothing else on the classpath is seen. Returns {:specs [..] :errors [..]}.(project-paths path)The classpath entries path stands for. A directory holding a deps.edn
contributes its :paths (default ["src"]) resolved against it; anything
else — a plain source dir, a jar — is itself the one entry.
The classpath entries `path` stands for. A directory holding a deps.edn contributes its :paths (default ["src"]) resolved against it; anything else — a plain source dir, a jar — is itself the one entry.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |