<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Clojure Q&amp;A - Recent questions tagged tools.namespace</title>
<link>https://ask.clojure.org/index.php/tag/tools.namespace</link>
<description></description>
<item>
<title>tools.namespace remove-node does not remove outgoing dependencies from :dependents</title>
<link>https://ask.clojure.org/index.php/14345/namespace-remove-remove-outgoing-dependencies-dependents</link>
<description>&lt;h3&gt;Problem&lt;/h3&gt;
&lt;p&gt;I noticed that when a dependency, &lt;code&gt;example.one&lt;/code&gt;, was removed from another namespace, &lt;code&gt;example.two&lt;/code&gt;, &lt;code&gt;example.one&lt;/code&gt; still showed up under &lt;code&gt;[::track/deps :dependents 'example.two]&lt;/code&gt; in the tracker after an invocation of &lt;code&gt;repl/scan&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After digging into this for some time, I saw that the implementation of &lt;code&gt;remove-node&lt;/code&gt; in &lt;code&gt;MapDependencyGraph&lt;/code&gt; didn't make any changes to the &lt;code&gt;:dependents&lt;/code&gt; attribute.&lt;/p&gt;
&lt;p&gt;This seems like a mistake to me, as the &lt;code&gt;remove-node&lt;/code&gt; docstring reads:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Removes the node from the dependency graph without removing it as a&lt;br&gt;
dependency of other nodes. That is, removes all outgoing edges from&lt;br&gt;
node.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The implementation of &lt;code&gt;remove-node&lt;/code&gt; follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(remove-node [graph node]
  (MapDependencyGraph.
    (dissoc dependencies node)
    dependents))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This removes outgoing edges from &lt;code&gt;dependencies&lt;/code&gt;, but if &lt;code&gt;dependents&lt;/code&gt; is effectively an inverse of &lt;code&gt;dependencies&lt;/code&gt;, then I'd expect to see some sort of removal from &lt;code&gt;dependents&lt;/code&gt; as well. Instead, &lt;code&gt;dependents&lt;/code&gt; remains unmodified.&lt;/p&gt;
&lt;h3&gt;Proposed Fix&lt;/h3&gt;
&lt;p&gt;If this is indeed a bug, and not a misunderstanding on my part, I have a fix &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/brandoncorrea/tools.namespace/commit/8ee0608a1885826ac862382c282e718bb4aae850&quot;&gt;here&lt;/a&gt; along with &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/brandoncorrea/tools.namespace/blob/behavioral-tests/src/test/clojure/clojure/tools/namespace/repl_test.clj#L56-L80&quot;&gt;a couple tests&lt;/a&gt; on my &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/brandoncorrea/tools.namespace/tree/behavioral-tests&quot;&gt;behavioral-tests branch&lt;/a&gt; that removes &lt;code&gt;node&lt;/code&gt; from values in the &lt;code&gt;dependents&lt;/code&gt; map.&lt;/p&gt;
&lt;p&gt;Does this align with the expected behavior of &lt;code&gt;remove-node&lt;/code&gt;, or am I misunderstanding the intended behavior of this function?&lt;/p&gt;
</description>
<category>tools.namespace</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/14345/namespace-remove-remove-outgoing-dependencies-dependents</guid>
<pubDate>Mon, 20 Jan 2025 02:32:44 +0000</pubDate>
</item>
<item>
<title>CLR behavior of tools.namespace does not match the JVM implementation</title>
<link>https://ask.clojure.org/index.php/14284/clr-behavior-tools-namespace-does-not-match-implementation</link>
<description>&lt;p&gt;I noticed a few behavioral differences between the CLR and JVM implementations of &lt;code&gt;tools.namespace&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As an example, the following tests will pass in the JVM implementation and fail in the CLR implementation. In CLR, &lt;code&gt;files-2&lt;/code&gt; is empty and &lt;code&gt;::dir/time&lt;/code&gt; is an instant.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(ns clojure.tools.namespace.repl-test
  (:require [clojure.test :refer [deftest is]]
            [clojure.tools.namespace.dir :as dir]
            [clojure.tools.namespace.find :as find]
            [clojure.tools.namespace.repl :as repl]
            [clojure.tools.namespace.test-helpers :as help]))

(deftest t-repl-scan
  (let [dir        (help/create-temp-dir &quot;t-repl-scan&quot;)
        _main-clj  (help/create-source dir 'example.main :clj '[example.one])
        _one-cljc  (help/create-source dir 'example.one :clj)
        _other-dir (help/create-temp-dir &quot;t-repl-scan-other&quot;)
        files-1    (::dir/files (repl/scan {:platform find/clj}))
        files-2    (::dir/files (repl/scan {:platform find/clj}))]
    (is (not-empty files-1))
    (is (not-empty files-2))
    (is (= files-1 files-2))))

(deftest t-repl-scan-time
  (let [scan (repl/scan {:platform find/clj})]
    (is (integer? (::dir/time scan)))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After discussing with other contributors, the question of intent came up and this test was proposed as something that correctly captures the intent of &lt;code&gt;repl/scan&lt;/code&gt;. However, if this is the intended behavior, then a new problem arises as this test fails in the JVM implementation.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(deftest t-repl-scan
  (try
    (let [dir       (help/create-temp-dir &quot;t-repl-scan&quot;)
          _main-clj (help/create-source dir 'example.main :clj '[example.one])
          _one-cljc (help/create-source dir 'example.one :clj)
          other-dir (help/create-temp-dir &quot;t-repl-scan-other&quot;)
          _         (repl/set-refresh-dirs dir other-dir)
          scan1     (repl/scan {:platform find/clj})
          scan2     (repl/scan {:platform find/clj})
          files-1   (::dir/files scan1)
          files-2   (::dir/files scan2)]
      (is (= (count files-1) 2))
      (is (= (count files-2) 0)))
    (finally (repl/clear))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A couple things I think would help here:&lt;br&gt;
 1. Flesh out the &lt;code&gt;tools.namespace&lt;/code&gt; (JVM) test suite to capture all the intended behavior.&lt;br&gt;
 2. Realign &lt;code&gt;clr.tools.namespace&lt;/code&gt; with &lt;code&gt;tools.namespace&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Point 1 will provide a good baseline for point 2, as well as any other existing/future ports of &lt;code&gt;tools.namespace&lt;/code&gt; and help prevent things from diverging in the future as changes are made.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As of writing, &lt;code&gt;repl/scan&lt;/code&gt; will throw an &lt;code&gt;InvalidCastException&lt;/code&gt; on CLR. To fix this, replace &lt;code&gt;clojure.tools.namespace.dir/modified-files&lt;/code&gt; with this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(defn- modified-files [tracker files]
  (filter #(DateTime/op_LessThan ^DateTime (::time tracker System.DateTime/UnixEpoch) (.get_LastWriteTimeUtc ^FileSystemInfo %)) files))
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>ClojureCLR</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/14284/clr-behavior-tools-namespace-does-not-match-implementation</guid>
<pubDate>Thu, 05 Dec 2024 14:44:05 +0000</pubDate>
</item>
<item>
<title>clojure.tools.namespace throws casting error when calling find-ns-decls-in-jarfile</title>
<link>https://ask.clojure.org/index.php/12732/clojure-tools-namespace-throws-casting-error-calling-jarfile</link>
<description>&lt;p&gt;If I call &lt;code&gt;find-ns-decls-in-jarfile jarfile&lt;/code&gt; (example below) with any jar I get the exception:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Error printing return value (ClassCastException) at clojure.tools.namespace.find/read-ns-decl-from-jarfile-entry (find.clj:158).&lt;br&gt;
class java.util.jar.JarFile cannot be cast to class java.io.File (java.util.jar.JarFile and java.io.File are in module java.base of loader 'bootstrap')&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I can reproduce this with this example:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
    (let [filename (format &quot;%s/.m2/repository/org/clojure/tools.namespace/1.4.2/tools.namespace-1.4.2.jar&quot; (System/getenv &quot;HOME&quot;))
      jarfile (JarFile. (io/file filename))]
  (clojure.tools.namespace.find/find-ns-decls-in-jarfile jarfile))
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;I think the issue is the &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/clojure/tools.namespace/blob/master/src/main/clojure/clojure/tools/namespace/find.clj#L159&quot;&gt;type hint on line 159&lt;/a&gt;. I think this should instead be &lt;code&gt;^java.util.jar.JarFile&lt;/code&gt;.&lt;/p&gt;
</description>
<category>tools.namespace</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/12732/clojure-tools-namespace-throws-casting-error-calling-jarfile</guid>
<pubDate>Tue, 07 Mar 2023 17:15:20 +0000</pubDate>
</item>
<item>
<title>How to restrict namespaces reloaded by tools.namespace to only dependencies of a root ns?</title>
<link>https://ask.clojure.org/index.php/12724/restrict-namespaces-reloaded-tools-namespace-dependencies</link>
<description>&lt;p&gt;Hey,&lt;/p&gt;
&lt;p&gt;At my organisation, we use Component and would like to start using the reloaded workflow to reload the code more easily.&lt;/p&gt;
&lt;p&gt;The problem we’re facing is that our dev classpath contains too much. In addition to the app proper (loaded by &lt;code&gt;(require 'our-org.repl)&lt;/code&gt;), there are tests and some one-off code: migrations and illustrative REPL sessions that we keep around as documentation.&lt;/p&gt;
&lt;p&gt;Some of these auxiliary namespaces have names that don’t match their location in the filesystem, so they are not loaded correctly by tools.namespace. We’d like to prevent them from being reloaded at all, even though they are present on the classpath.&lt;/p&gt;
&lt;p&gt;We could use &lt;code&gt;clojure.tools.namespace.repl/set-refresh-dirs&lt;/code&gt;, but I feel this is clunky (need to explicitly opt-in for directories) and not quite expressive enough. What we’d really want is to reload only the namespaces that are (possibly indirect) dependencies of &lt;code&gt;our-org.repl&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To this end, I’ve monkey-patched tools-namespace:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(defn relevant-deps [deps ns]
  (conj
   (ns.dependency/transitive-dependencies deps ns)
   ns))

(alter-var-root
 #'ns.repl/remove-disabled
 (fn [orig-impl]
   (fn [{:keys [::ns.track/deps] :as tracker}]
     (-&amp;gt; tracker
         (orig-impl)
         (update ::ns.track/unload (partial filter (loaded-libs)))
         (update ::ns.track/load
                 #(set/intersection (set %1) %2)
                 (relevant-deps deps 'our-org.repl))))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works, but is obviously kludgy. Is there a better way to achieve the same goal? Perhaps the functionality of restricting dependencies could be added to tools.namespace?&lt;/p&gt;
</description>
<category>tools.namespace</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/12724/restrict-namespaces-reloaded-tools-namespace-dependencies</guid>
<pubDate>Fri, 03 Mar 2023 20:17:19 +0000</pubDate>
</item>
<item>
<title>Should tools.namespace find still cope with namespace-less sources?</title>
<link>https://ask.clojure.org/index.php/12677/should-tools-namespace-find-still-cope-with-namespace-sources</link>
<description>&lt;p&gt;&lt;strong&gt;Issue&lt;/strong&gt;&lt;br&gt;
Tools.namespace find 1.4.1 does not handle sources that don't include a &lt;code&gt;ns&lt;/code&gt; declaration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reproduction&lt;/strong&gt;&lt;br&gt;
Given file &lt;code&gt;./src/foo.clj&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;;; no ns declaration here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And test script &lt;code&gt;./test.clj&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(require '[clojure.tools.namespace.find :as f]
         '[clojure.java.io :as io])

(println &quot;found nses:&quot; (f/find-ns-decls-in-dir (io/file &quot;src&quot;)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see that &lt;code&gt;tools.namespace 1.4.0&lt;/code&gt; returns an empty sequence for this scenario:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ clj -Sdeps '{:deps {org.clojure/tools.namespace {:mvn/version &quot;1.4.0&quot;}}}' -M --report stderr test.clj
found nses: ()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But version 1.4.1 throws an exception for this same test:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ clj -Sdeps '{:deps {org.clojure/tools.namespace {:mvn/version &quot;1.4.1&quot;}}}' -M --report stderr test.clj
{:clojure.main/message
 &quot;Execution error (NullPointerException) at clojure.tools.namespace.find/find-ns-decls-in-dir$fn (find.clj:93).\nCannot invoke \&quot;clojure.lang.IObj.withMeta(clojure.lang.IPersistentMap)\&quot; because \&quot;x\&quot; is null\n&quot;,
 :clojure.main/triage
 {:clojure.error/class java.lang.NullPointerException,
  :clojure.error/line 93,
  :clojure.error/cause
  &quot;Cannot invoke \&quot;clojure.lang.IObj.withMeta(clojure.lang.IPersistentMap)\&quot; because \&quot;x\&quot; is null&quot;,
  :clojure.error/symbol
  clojure.tools.namespace.find/find-ns-decls-in-dir$fn,
  :clojure.error/source &quot;find.clj&quot;,
  :clojure.error/phase :execution},
 :clojure.main/trace
 {:via
  [{:type clojure.lang.Compiler$CompilerException,
    :message
    &quot;Syntax error macroexpanding at (/home/lee/proj/oss/-verify/tns-test/test.clj:4:1).&quot;,
    :data
    {:clojure.error/phase :execution,
     :clojure.error/line 4,
     :clojure.error/column 1,
     :clojure.error/source
     &quot;/home/lee/proj/oss/-verify/tns-test/test.clj&quot;},
    :at [clojure.lang.Compiler load &quot;Compiler.java&quot; 7665]}
   {:type java.lang.NullPointerException,
    :message
    &quot;Cannot invoke \&quot;clojure.lang.IObj.withMeta(clojure.lang.IPersistentMap)\&quot; because \&quot;x\&quot; is null&quot;,
    :at [clojure.core$with_meta__5485 invokeStatic &quot;core.clj&quot; 220]}],
  :trace
  [[clojure.core$with_meta__5485 invokeStatic &quot;core.clj&quot; 220]
   [clojure.core$with_meta__5485 invoke &quot;core.clj&quot; 219]
   [clojure.tools.namespace.find$find_ns_decls_in_dir$fn__1437
    invoke
    &quot;find.clj&quot;
    93]
   [clojure.core$keep$fn__8649 invoke &quot;core.clj&quot; 7409]
   [clojure.lang.LazySeq sval &quot;LazySeq.java&quot; 42]
   [clojure.lang.LazySeq seq &quot;LazySeq.java&quot; 51]
   [clojure.lang.RT seq &quot;RT.java&quot; 535]
   [clojure.core$seq__5467 invokeStatic &quot;core.clj&quot; 139]
   [clojure.core$print_sequential invokeStatic &quot;core_print.clj&quot; 53]
   [clojure.core$fn__7391 invokeStatic &quot;core_print.clj&quot; 174]
   [clojure.core$fn__7391 invoke &quot;core_print.clj&quot; 174]
   [clojure.lang.MultiFn invoke &quot;MultiFn.java&quot; 234]
   [clojure.core$pr_on invokeStatic &quot;core.clj&quot; 3675]
   [clojure.core$pr invokeStatic &quot;core.clj&quot; 3678]
   [clojure.core$pr invoke &quot;core.clj&quot; 3678]
   [clojure.lang.AFn applyToHelper &quot;AFn.java&quot; 154]
   [clojure.lang.RestFn applyTo &quot;RestFn.java&quot; 132]
   [clojure.core$apply invokeStatic &quot;core.clj&quot; 667]
   [clojure.core$pr invokeStatic &quot;core.clj&quot; 3691]
   [clojure.core$pr doInvoke &quot;core.clj&quot; 3678]
   [clojure.lang.RestFn applyTo &quot;RestFn.java&quot; 139]
   [clojure.core$apply invokeStatic &quot;core.clj&quot; 667]
   [clojure.core$prn invokeStatic &quot;core.clj&quot; 3715]
   [clojure.core$prn doInvoke &quot;core.clj&quot; 3715]
   [clojure.lang.RestFn applyTo &quot;RestFn.java&quot; 137]
   [clojure.core$apply invokeStatic &quot;core.clj&quot; 667]
   [clojure.core$println invokeStatic &quot;core.clj&quot; 3734]
   [clojure.core$println doInvoke &quot;core.clj&quot; 3734]
   [clojure.lang.RestFn invoke &quot;RestFn.java&quot; 421]
   [user$eval1480 invokeStatic &quot;test.clj&quot; 4]
   [user$eval1480 invoke &quot;test.clj&quot; 4]
   [clojure.lang.Compiler eval &quot;Compiler.java&quot; 7194]
   [clojure.lang.Compiler load &quot;Compiler.java&quot; 7653]
   [clojure.lang.Compiler loadFile &quot;Compiler.java&quot; 7591]
   [clojure.main$load_script invokeStatic &quot;main.clj&quot; 475]
   [clojure.main$script_opt invokeStatic &quot;main.clj&quot; 535]
   [clojure.main$script_opt invoke &quot;main.clj&quot; 530]
   [clojure.main$main invokeStatic &quot;main.clj&quot; 664]
   [clojure.main$main doInvoke &quot;main.clj&quot; 616]
   [clojure.lang.RestFn applyTo &quot;RestFn.java&quot; 137]
   [clojure.lang.Var applyTo &quot;Var.java&quot; 705]
   [clojure.main main &quot;main.java&quot; 40]],
  :cause
  &quot;Cannot invoke \&quot;clojure.lang.IObj.withMeta(clojure.lang.IPersistentMap)\&quot; because \&quot;x\&quot; is null&quot;,
  :phase :execution}}

Execution error (NullPointerException) at clojure.tools.namespace.find/find-ns-decls-in-dir$fn (find.clj:93).
Cannot invoke &quot;clojure.lang.IObj.withMeta(clojure.lang.IPersistentMap)&quot; because &quot;x&quot; is null
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Usage Scenario&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Cljdoc uses tools.namespace to find namespaces during API analysis.&lt;/p&gt;
&lt;p&gt;Various libs include all sorts of weirdnesses including namespace-less sources.&lt;/p&gt;
&lt;p&gt;Previous versions of tools.namespace handled this weirdness for us.&lt;/p&gt;
&lt;p&gt;We can certainly work around this if it is decided that tools.namespace should not handle namespace-less sources.&lt;/p&gt;
</description>
<category>tools.namespace</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/12677/should-tools-namespace-find-still-cope-with-namespace-sources</guid>
<pubDate>Tue, 21 Feb 2023 20:17:47 +0000</pubDate>
</item>
<item>
<title>Exposing namespaces that will be reloaded from c.t.n.repl</title>
<link>https://ask.clojure.org/index.php/12231/exposing-namespaces-that-will-be-reloaded-from-c-t-n-repl</link>
<description>&lt;p&gt;Hello! I've recently copied some logic out of clojure.tools.namespace.repl that determines the next set of namespaces that need refreshing: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/clojure/tools.namespace/blob/master/src/main/clojure/clojure/tools/namespace/repl.clj#L91&quot;&gt;https://github.com/clojure/tools.namespace/blob/master/src/main/clojure/clojure/tools/namespace/repl.clj#L91&lt;/a&gt; This information is highly useful to external consumers who may need to manage some stateful resources prior to refreshing, depending on their state management solution.&lt;/p&gt;
&lt;p&gt;I opened a PR here, which was closed because I apparently can't read contribution guidelines: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/clojure/tools.namespace/pull/13&quot;&gt;https://github.com/clojure/tools.namespace/pull/13&lt;/a&gt; This just pulls out functions that are invoked via &lt;code&gt;alter-var-root&lt;/code&gt; to a standalone function. (vemv also helpfully pointed out that I forgot to propagate an argument).&lt;/p&gt;
&lt;p&gt;Would this be a reasonable, small change to make to c.t.n.repl?&lt;/p&gt;
&lt;p&gt;Thank you :)&lt;/p&gt;
</description>
<category>tools.namespace</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/12231/exposing-namespaces-that-will-be-reloaded-from-c-t-n-repl</guid>
<pubDate>Fri, 23 Sep 2022 22:42:10 +0000</pubDate>
</item>
<item>
<title>tools.namespace does not recognise ns deps implied by data_readers.cljc</title>
<link>https://ask.clojure.org/index.php/11845/tools-namespace-does-recognise-deps-implied-datareaders</link>
<description>&lt;p&gt;i found an interesting issue in our codebase around some tagged-literals seemingly violating the principle of least surprise&lt;/p&gt;
&lt;p&gt;we have been creating some pure-data descriptions of processes including some &lt;code&gt;defrecord&lt;/code&gt; objects from a custom tagged-literal reader declared in &lt;code&gt;data_readers.cljc&lt;/code&gt;, and having those &lt;code&gt;defrecord&lt;/code&gt; objects participate in a protocol. it's all been working just fine until i ran across this issue&lt;/p&gt;
&lt;p&gt;someone had put one of these tagged literals into a &lt;code&gt;def&lt;/code&gt; (which seemed like a reasonable thing to do at first blush):&lt;/p&gt;
&lt;p&gt;&lt;code&gt;(def foo #ctx/event-path [:blah])&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;which was ok... until &lt;code&gt;c.t.n.r/refresh&lt;/code&gt; was called, after which point everything broke&lt;/p&gt;
&lt;p&gt;it turned out that the &lt;code&gt;defrecord&lt;/code&gt; object &lt;code&gt;foo&lt;/code&gt; had a stale class (presumably because the namespace dependencies induced by the tagged-literal parsers declared in &lt;code&gt;data_readers.cljc&lt;/code&gt; are not recognised by &lt;code&gt;tools.namespace&lt;/code&gt;, and namespaces were therefore recompiled out of order), and so no longer participated in the protocol&lt;/p&gt;
&lt;p&gt;should &lt;code&gt;tools.namespace&lt;/code&gt; be able to recognise &lt;code&gt;data_readers.cljc&lt;/code&gt; induced dependencies ? or is that a step too far for it ?&lt;/p&gt;
</description>
<category>tools.namespace</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/11845/tools-namespace-does-recognise-deps-implied-datareaders</guid>
<pubDate>Fri, 29 Apr 2022 14:52:37 +0000</pubDate>
</item>
<item>
<title>Could tools.namespace refresh get more sophisticated directory/file filtering?</title>
<link>https://ask.clojure.org/index.php/11434/could-namespace-refresh-sophisticated-directory-filtering</link>
<description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;&lt;br&gt;
currently the only way of affecting which source files are loaded by &lt;code&gt;clojure.tools.namespace.repl/refresh&lt;/code&gt; is setting refresh dirs, which is an allowlist-based system. There is no way currently to &lt;em&gt;block&lt;/em&gt; specific directories/files/patterns from being loaded but allowing everything else. This presents an issue when there are clojure source files in source directories on the classpath, which are not meant to be loaded at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Long story:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We bumped into an interesting issue with &lt;code&gt;clojure.tools.namespace/refresh&lt;/code&gt; vs &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/clj-kondo/clj-kondo/blob/master/doc/hooks.md&quot;&gt;clj-kondo hooks&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;A one-liner repro case is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clj -Srepro -Sdeps '{:deps {org.clojure/tools.namespace {:mvn/version &quot;1.2.0&quot;} seancorfield/next.jdbc {:git/url &quot;https://github.com/seancorfield/next-jdbc/&quot; :git/sha &quot;24bf1dbaa441d62461f980e9f880df5013f295dd&quot;}}}' -M -e &quot;((requiring-resolve 'clojure.tools.namespace.repl/refresh-all))&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will fail with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:error-while-loading hooks.com.github.seancorfield.next-jdbc
Could not locate hooks/com/github/seancorfield/next_jdbc__init.class, hooks/com/github/seancorfield/next_jdbc.clj or hooks/com/github/seancorfield/next_jdbc.cljc on classpath. Please check that namespaces with dashes use underscores in the Clojure file name.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For context, clj-kondo is a static analyzer/linter. In order to be able to analyze custom macros properly, it lets libraries distribute clj files (describing how these macros should be analyzed) as resources under a specific directory.&lt;/p&gt;
&lt;p&gt;The above example fails due to the combination of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;referring a lib by git coordinates, which means that it will appear as a directory on the classpath&lt;/li&gt;
&lt;li&gt;said lib exporting clj-kondo hooks&lt;/li&gt;
&lt;li&gt;clj-kondo hooks themselves being .clj files&lt;/li&gt;
&lt;li&gt;as these are for clj-kondo to use, they are not meant to be loaded in the app using the lib&lt;/li&gt;
&lt;li&gt;as a result these files normally having a namespace inside them that does not appear in code proper, for example: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/seancorfield/next-jdbc/blob/24bf1dbaa441d62461f980e9f880df5013f295dd/resources/clj-kondo.exports/com.github.seancorfield/next.jdbc/hooks/com/github/seancorfield/next_jdbc.clj#L1&quot;&gt;https://github.com/seancorfield/next-jdbc/blob/24bf1dbaa441d62461f980e9f880df5013f295dd/resources/clj-kondo.exports/com.github.seancorfield/next.jdbc/hooks/com/github/seancorfield/next_jdbc.clj#L1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tools.namespace by default reloads all clj source files found in &lt;a rel=&quot;nofollow&quot; href=&quot;https://clojure.github.io/java.classpath/#clojure.java.classpath/classpath-directories&quot;&gt;classpath-directories&lt;/a&gt; (referring back to the first point)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As there is currently no way to tell tools.namespace to &lt;em&gt;not&lt;/em&gt; load certain files I had to come up with a somewhat hacky workaround, which tries to set the refresh dirs to classpath-directories minus problematic ones, but it would be much much nicer if there was a way to be able to set this with a blocklist or predicate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Workaround&lt;/strong&gt; in case anyone else bumps into it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(defn remove-clj-kondo-exports-from-tools-ns-refresh-dirs
  &quot;A potential issue from using this is that if the directory containing the clj-kondo.exports folder
  also directly contains to-be-reloaded clojure source files, those will no longer be reloaded.&quot;
  []
  (-&amp;gt;&amp;gt; (clojure.java.classpath/classpath-directories)
       (mapcat
        (fn [^File classpath-directory]
          (let [children   (.listFiles classpath-directory)
                directory? #(.isDirectory ^File %)
                clj-kondo-exports?
                           #(= &quot;clj-kondo.exports&quot; (.getName ^File %))
                has-clj-kondo-exports
                           (some (every-pred clj-kondo-exports? directory?) children)]
            (if has-clj-kondo-exports
              (-&amp;gt;&amp;gt; children
                   (filter directory?)
                   (remove clj-kondo-exports?))
              [classpath-directory]))))
       (apply clojure.tools.namespace.repl/set-refresh-dirs)))

;; call in user.clj
(remove-clj-kondo-exports-from-tools-ns-refresh-dirs)
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>tools.namespace</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/11434/could-namespace-refresh-sophisticated-directory-filtering</guid>
<pubDate>Wed, 05 Jan 2022 18:03:20 +0000</pubDate>
</item>
<item>
<title>Resolution for bug TNS-6 in clojure.tools.namespace</title>
<link>https://ask.clojure.org/index.php/10655/resolution-for-bug-tns-6-in-clojure-tools-namespace</link>
<description>&lt;p&gt;Hi there,&lt;/p&gt;
&lt;p&gt;So I believe I have a resolution for &lt;a rel=&quot;nofollow&quot; href=&quot;https://clojure.atlassian.net/browse/TNS-6&quot;&gt;TNS-6&lt;/a&gt; in clojure.tools.namespace. I have a consistent repro and a resolution in the form of a one-line patch (see the patch for more detail). All the tests still pass, though I'm not sure they cover the changes. I have also tested the resolution in a number of local dependent repos, and it resolves the issue.&lt;/p&gt;
&lt;p&gt;However, I am not a Clojure contributor so I cannot comment or submitt the patch or comment on relevant Jira ticket.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;From b5a62f894e049a09d5fcf099ac7b4d6591fb4f18 Mon Sep 17 00:00:00 2001
From: zalky &amp;lt;zalan.k@gmail.com&amp;gt;
Date: Mon, 24 May 2021 13:08:30 -0400
Subject: [PATCH] Fix TNS-6: fully remove ns from deps graph

The clojure.tools.namespace.dependency/remove-node fn removes a
namespace's :dependencies set from the graph (outgoing edges), but
does not remove that namespace from the :dependents set of other
namespaces (ingoing edges). If a namespace is removed and one of its
dependencies is changed at the same time, as commonly occurs when
switching branches, then the removed namespace is still in the
:dependents of the changed namespace when it is reloaded. As all the
of the dependents of a changed namespace are also reloaded, this
throws a missing namespace error.

The resolution is to use clojure.tools.namespace.depedency/remove-all
to remove both outgoing (:dependencies) and ingoing (:dependents)
edges in the dependency graph.

However, care must be taken when choosing the point of change, because
clojure.tools.namespace.track/add relies on the partial removal
behaviour of clojure.tools.namespace.track/remove-deps. It uses
remove-deps to wipe the dependencies of a node, and cannot know how to
re-insert dependents if lost. Therefore the point of change should be
in clojure.tools.namespace.track/remove.
---
 src/main/clojure/clojure/tools/namespace/track.cljc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/clojure/clojure/tools/namespace/track.cljc b/src/main/clojure/clojure/tools/namespace/track.cljc
index 683c35d..ce666d5 100644
--- a/src/main/clojure/clojure/tools/namespace/track.cljc
+++ b/src/main/clojure/clojure/tools/namespace/track.cljc
@@ -96,7 +96,7 @@
          :or {load (), unload (), deps (dep/graph)}} tracker
         known (set (dep/nodes deps))
         removed-names (filter known names)
-        new-deps (remove-deps deps removed-names)
+        new-deps (reduce dep/remove-all deps removed-names)
         changed (affected-namespaces deps removed-names)]
     (assoc tracker
       ::deps new-deps
-- 
2.30.1 (Apple Git-130)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;[Patch updated after further testing]&lt;/p&gt;
</description>
<category>tools.namespace</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/10655/resolution-for-bug-tns-6-in-clojure-tools-namespace</guid>
<pubDate>Mon, 24 May 2021 17:39:12 +0000</pubDate>
</item>
<item>
<title>Would be nice if tools.namespace.find functions return file info in ns-decl meta</title>
<link>https://ask.clojure.org/index.php/8826/would-nice-tools-namespace-find-functions-return-file-info</link>
<description>&lt;p&gt;Currently calling &lt;code&gt;tools.namespace.find/find-ns-decls&lt;/code&gt; returns a seq of ns-decl for a given dir or collection of paths but there is no way to know where did they came from (can also be coming from paths inside jar files).&lt;/p&gt;
&lt;p&gt;Looks pretty straight forward to add file info as meta of the ns-decl form. Something like &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/jpmonettas/tools.namespace/commit/1431215324ba7f76f78342742ce3716ec8c5abb8&quot;&gt;https://github.com/jpmonettas/tools.namespace/commit/1431215324ba7f76f78342742ce3716ec8c5abb8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What do you guys think?&lt;/p&gt;
&lt;p&gt;(Filed jira at &lt;a rel=&quot;nofollow&quot; href=&quot;https://clojure.atlassian.net/browse/TNS-55&quot;&gt;https://clojure.atlassian.net/browse/TNS-55&lt;/a&gt;)&lt;/p&gt;
</description>
<category>tools.namespace</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/8826/would-nice-tools-namespace-find-functions-return-file-info</guid>
<pubDate>Tue, 05 Nov 2019 13:35:01 +0000</pubDate>
</item>
<item>
<title>How does tools.namespace.track/add is supposed to work?</title>
<link>https://ask.clojure.org/index.php/8737/how-does-tools-namespace-track-add-is-supposed-to-work</link>
<description>&lt;p&gt;I'm trying to figure out if I can use tools.namespace.track for a project but I don't understand the :unload :load functionality.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(require '[clojure.tools.namespace.track :as ns-track])

;; define a empty tracker and add some dependencies
(def tracker (-&amp;gt; (ns-track/tracker)
                 (ns-track/add '{alpha #{beta}
                                 beta  #{gamma delta}})))

;; now add a new dependency and check what we need to unload and load
(-&amp;gt; tracker
    (ns-track/add '{epsilon #{}})
    (select-keys [:clojure.tools.namespace.track/unload
                  :clojure.tools.namespace.track/load]))

#:clojure.tools.namespace.track{:unload (epsilon alpha beta),
                                :load (epsilon beta alpha)}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I don't understand why alpha and  beta are required to unload/load but maybe I'm missing something.&lt;/p&gt;
&lt;p&gt;I'm using the latest version.&lt;/p&gt;
&lt;p&gt;Thanks!&lt;/p&gt;
</description>
<category>tools.namespace</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/8737/how-does-tools-namespace-track-add-is-supposed-to-work</guid>
<pubDate>Fri, 18 Oct 2019 21:22:25 +0000</pubDate>
</item>
<item>
<title>Java 11 and Tools Namespace</title>
<link>https://ask.clojure.org/index.php/8288/java-11-and-tools-namespace</link>
<description>&lt;p&gt;I've run into an issue where &lt;code&gt;refresh&lt;/code&gt; from &lt;code&gt;tools.namespace&lt;/code&gt; (v. &lt;code&gt;0.3.0&lt;/code&gt;) seems to work with Java 8 but not Java 11. I tried with both Clojure &lt;code&gt;1.10.0&lt;/code&gt; and &lt;code&gt;1.10.1&lt;/code&gt;. I was able to reproduce the problem on a clean virtual machine. In both cases, I was able to reload the namespaces on Java 8 but not Java 11.&lt;/p&gt;
&lt;p&gt;It's weird though -- in some of my other projects, I can reload namespaces on Java 11. I haven't been able to track down the difference. (I'm also new to &lt;code&gt;tools.deps&lt;/code&gt;, so it could be I'm doing something wrong there.)&lt;/p&gt;
&lt;p&gt;I put together a reproduction here: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/thomascothran/namespace-repro&quot;&gt;https://github.com/thomascothran/namespace-repro&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I'm assuming it's likely an error on my end, but the only thing I've been able to narrow it down to is the Java version.&lt;/p&gt;
&lt;p&gt;Reference: &lt;a rel=&quot;nofollow&quot; href=&quot;https://clojure.atlassian.net/browse/TNS-54&quot;&gt;https://clojure.atlassian.net/browse/TNS-54&lt;/a&gt;&lt;/p&gt;
</description>
<category>tools.namespace</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/8288/java-11-and-tools-namespace</guid>
<pubDate>Wed, 31 Jul 2019 14:50:56 +0000</pubDate>
</item>
</channel>
</rss>