|
156 | 156 | deps (set/union (set/difference (into #{} (map (comp symbol var->protocol)) @!deps) vars) |
157 | 157 | deref-deps |
158 | 158 | (when (var? form) #{(symbol form)})) |
159 | | - hash-fn (-> form meta :nextjournal.clerk/hash-fn)] |
| 159 | + hash-fn (-> form meta :nextjournal.clerk/hash-fn) |
| 160 | + macro? (-> analyzed :env :defmacro)] |
160 | 161 | (cond-> {#_#_:analyzed analyzed |
161 | 162 | :form form |
162 | 163 | :ns-effect? (some? (some #{'clojure.core/require 'clojure.core/in-ns} deps)) |
163 | 164 | :freezable? (and (not (some #{'clojure.core/intern} deps)) |
164 | 165 | (<= (count vars) 1) |
165 | 166 | (if (seq vars) (= var (first vars)) true)) |
166 | | - :no-cache? (no-cache? form (-> def-node :form second) *ns*)} |
| 167 | + :no-cache? (no-cache? form (-> def-node :form second) *ns*) |
| 168 | + :macro macro?} |
167 | 169 | hash-fn (assoc :hash-fn hash-fn) |
168 | 170 | (seq deps) (assoc :deps deps) |
169 | 171 | (seq deref-deps) (assoc :deref-deps deref-deps) |
|
335 | 337 | (let [{:as form-analysis :keys [ns-effect? form]} (cond-> (analyze (:form block)) |
336 | 338 | (:file doc) (assoc :file (:file doc))) |
337 | 339 | block+analysis (add-block-id (merge block form-analysis))] |
338 | | - (when ns-effect? ;; needs to run before setting doc `:ns` via `*ns*` |
| 340 | + (when ns-effect? |
339 | 341 | (eval form)) |
340 | 342 | (-> state |
341 | 343 | (store-info block+analysis) |
|
442 | 444 |
|
443 | 445 | (defn var->location [var] |
444 | 446 | (when-let [file (:file (meta var))] |
445 | | - (some-> (if (fs/absolute? file) |
| 447 | + (some-> (if (try (fs/absolute? file) |
| 448 | + ;; fs/absolute? crashes in bb on Windows due to the :file |
| 449 | + ;; metadata containing "<expr>" |
| 450 | + (catch Exception _ false)) |
446 | 451 | (when (fs/exists? file) |
447 | 452 | (fs/relativize (fs/cwd) (fs/file file))) |
448 | 453 | (when-let [resource (io/resource file)] |
|
496 | 501 | (filter (comp #{:code} :type) |
497 | 502 | blocks)))) |
498 | 503 |
|
| 504 | +(defn transitive-deps |
| 505 | + ([id analysis-info] |
| 506 | + (loop [seen #{} |
| 507 | + deps #{id} |
| 508 | + res #{}] |
| 509 | + (if (seq deps) |
| 510 | + (let [dep (first deps)] |
| 511 | + (if (contains? seen dep) |
| 512 | + (recur seen (rest deps) res) |
| 513 | + (let [{new-deps :deps} (get analysis-info dep) |
| 514 | + seen (conj seen dep) |
| 515 | + deps (concat (rest deps) new-deps) |
| 516 | + res (into res deps)] |
| 517 | + (recur seen deps res)))) |
| 518 | + res)))) |
| 519 | + |
| 520 | +#_(transitive-deps id analysis-info) |
| 521 | + |
| 522 | +#_(transitive-deps :main {:main {:deps [:main :other]} |
| 523 | + :other {:deps [:another]} |
| 524 | + :another {:deps [:another-one :another :main]}}) |
| 525 | + |
| 526 | +(defn run-macros [init-state] |
| 527 | + (let [{:keys [blocks ->analysis-info]} init-state |
| 528 | + macro-block-ids (keep #(when (:macro %) |
| 529 | + (:id %)) blocks) |
| 530 | + deps (mapcat #(transitive-deps % ->analysis-info) macro-block-ids) |
| 531 | + all-block-ids (into (set macro-block-ids) deps) |
| 532 | + all-blocks (filter #(contains? all-block-ids (:id %)) blocks)] |
| 533 | + (doseq [block all-blocks] |
| 534 | + (try |
| 535 | + ;; (println "loading in namespace" *ns* (:text block)) |
| 536 | + (load-string (:text block)) |
| 537 | + (catch Throwable e |
| 538 | + (binding [*out* *err*] |
| 539 | + (println "Error when evaluating macro deps:" (:text block)) |
| 540 | + (println "Namespace:" *ns*) |
| 541 | + (println "Exception:" e))))) |
| 542 | + (pos? (count all-blocks)))) |
| 543 | + |
499 | 544 | (defn build-graph |
500 | 545 | "Analyzes the forms in the given file and builds a dependency graph of the vars. |
501 | 546 |
|
502 | | - Recursively decends into dependency vars as well as given they can be found in the classpath. |
| 547 | + Recursively descends into dependency vars as well if they can be found in the classpath. |
503 | 548 | " |
504 | 549 | [doc] |
505 | | - (loop [{:as state :keys [->analysis-info analyzed-file-set counter]} |
506 | | - (-> doc |
507 | | - analyze-doc |
508 | | - (assoc :analyzed-file-set (cond-> #{} (:file doc) (conj (:file doc))) |
509 | | - :counter 0 |
510 | | - :graph (dep/graph)))] |
511 | | - (let [unhashed (unhashed-deps ->analysis-info) |
512 | | - loc->syms (apply dissoc |
513 | | - (group-by find-location unhashed) |
514 | | - analyzed-file-set)] |
515 | | - (if (and (seq loc->syms) (< counter 10)) |
516 | | - (recur (-> (reduce (fn [g [source symbols]] |
517 | | - (let [jar? (or (nil? source) |
518 | | - (str/ends-with? source ".jar")) |
519 | | - gitlib-hash (and (not jar?) |
520 | | - (second (re-find #".gitlibs/libs/.*/(\b[0-9a-f]{5,40}\b)/" (fs/unixify source))))] |
521 | | - (if (or jar? gitlib-hash) |
522 | | - (update g :->analysis-info merge (into {} (map (juxt identity |
523 | | - (constantly (if source |
524 | | - (or (when gitlib-hash {:hash gitlib-hash}) |
525 | | - (hash-jar source)) |
526 | | - {})))) symbols)) |
527 | | - (-> g |
528 | | - (update :analyzed-file-set conj source) |
529 | | - (merge-analysis-info (analyze-file source)))))) |
530 | | - state |
531 | | - loc->syms) |
532 | | - (update :counter inc))) |
533 | | - (-> state |
534 | | - analyze-doc-deps |
535 | | - set-no-cache-on-redefs |
536 | | - make-deps-inherit-no-cache |
537 | | - (dissoc :analyzed-file-set :counter)))))) |
| 550 | + (binding [*ns* (:ns doc)] |
| 551 | + (let [init-state-fn #(-> doc |
| 552 | + analyze-doc |
| 553 | + (assoc :analyzed-file-set (cond-> #{} (:file doc) (conj (:file doc))) |
| 554 | + :counter 0 |
| 555 | + :graph (dep/graph))) |
| 556 | + init-state (init-state-fn) |
| 557 | + ran-macros? (run-macros init-state) |
| 558 | + init-state (if ran-macros? |
| 559 | + (init-state-fn) |
| 560 | + init-state)] |
| 561 | + (loop [{:as state :keys [->analysis-info analyzed-file-set counter]} init-state] |
| 562 | + (let [unhashed (unhashed-deps ->analysis-info) |
| 563 | + loc->syms (apply dissoc |
| 564 | + (group-by find-location unhashed) |
| 565 | + analyzed-file-set)] |
| 566 | + (if (and (seq loc->syms) (< counter 10)) |
| 567 | + (recur (-> (reduce (fn [g [source symbols]] |
| 568 | + (let [jar? (or (nil? source) |
| 569 | + (str/ends-with? source ".jar")) |
| 570 | + gitlib-hash (and (not jar?) |
| 571 | + (second (re-find #".gitlibs/libs/.*/(\b[0-9a-f]{5,40}\b)/" (fs/unixify source))))] |
| 572 | + (if (or jar? gitlib-hash) |
| 573 | + (update g :->analysis-info merge (into {} (map (juxt identity |
| 574 | + (constantly (if source |
| 575 | + (or (when gitlib-hash {:hash gitlib-hash}) |
| 576 | + (hash-jar source)) |
| 577 | + {})))) symbols)) |
| 578 | + (-> g |
| 579 | + (update :analyzed-file-set conj source) |
| 580 | + (merge-analysis-info (analyze-file source)))))) |
| 581 | + state |
| 582 | + loc->syms) |
| 583 | + (update :counter inc))) |
| 584 | + (-> state |
| 585 | + analyze-doc-deps |
| 586 | + set-no-cache-on-redefs |
| 587 | + make-deps-inherit-no-cache |
| 588 | + (dissoc :analyzed-file-set :counter)))))))) |
538 | 589 |
|
539 | 590 | (comment |
540 | 591 | (reset! !file->analysis-cache {}) |
|
0 commit comments