lambdaisland / deep-diff2

Deep diff Clojure data structures and pretty print the result
Eclipse Public License 1.0
296 stars 18 forks source link

Cljdoc analysis is failing #26

Closed lread closed 2 years ago

lread commented 2 years ago

Issue

Cljdoc analysis is failing for the much loved deep-diff2

(I'm going to assume you care because you have a cljdoc badge on your readme 🙂)

Symptom

Analysis job shows (logs aren't saved forever so I'll paste too):

2022-05-16 06:36:27,679 ERROR cljdoc-analyzer.runner - STDERR
 {:clojure.main/message
 "Execution error (FileNotFoundException) at lambdaisland.deep-diff2.diff-test/eval4071$loading (diff_test.cljc:1).\nCould not locate clojure/test/check__init.class, clojure/test/check.clj or clojure/test/check.cljc on classpath.\n",
 :clojure.main/triage
 {:clojure.error/class java.io.FileNotFoundException,
  :clojure.error/line 1,
  :clojure.error/cause
  "Could not locate clojure/test/check__init.class, clojure/test/check.clj or clojure/test/check.cljc on classpath.",
  :clojure.error/symbol
  lambdaisland.deep-diff2.diff-test/eval4071$loading,
  :clojure.error/source "diff_test.cljc",
  :clojure.error/phase :execution},
 :clojure.main/trace
 {:via
  [{:type clojure.lang.ExceptionInfo,
    :message
    "Could not generate Clojure documentation for lambdaisland.deep-diff2.diff-test",
    :data {},
    :at
    [cljdoc_analyzer.metagetta.utils$default_exception_handler
     invokeStatic
     "utils.clj"
     118]}
   {:type clojure.lang.Compiler$CompilerException,
    :message
    "Syntax error compiling at (lambdaisland/deep_diff2/diff_test.cljc:1:1).",
    :data
    {:clojure.error/phase :compile-syntax-check,
     :clojure.error/line 1,
     :clojure.error/column 1,
     :clojure.error/source "lambdaisland/deep_diff2/diff_test.cljc"},
    :at [clojure.lang.Compiler load "Compiler.java" 7648]}
   {:type java.io.FileNotFoundException,
    :message
    "Could not locate clojure/test/check__init.class, clojure/test/check.clj or clojure/test/check.cljc on classpath.",
    :at [clojure.lang.RT load "RT.java" 462]}],
  :trace
  [[clojure.lang.RT load "RT.java" 462]
   [clojure.lang.RT load "RT.java" 424]
   [clojure.core$load$fn__6839 invoke "core.clj" 6126]
   [clojure.core$load invokeStatic "core.clj" 6125]
   [clojure.core$load doInvoke "core.clj" 6109]
   [clojure.lang.RestFn invoke "RestFn.java" 408]
   [clojure.core$load_one invokeStatic "core.clj" 5908]
   [clojure.core$load_one invoke "core.clj" 5903]
   [clojure.core$load_lib$fn__6780 invoke "core.clj" 5948]
   [clojure.core$load_lib invokeStatic "core.clj" 5947]
   [clojure.core$load_lib doInvoke "core.clj" 5928]
   [clojure.lang.RestFn applyTo "RestFn.java" 142]
   [clojure.core$apply invokeStatic "core.clj" 667]
   [clojure.core$load_libs invokeStatic "core.clj" 5985]
   [clojure.core$load_libs doInvoke "core.clj" 5969]
   [clojure.lang.RestFn applyTo "RestFn.java" 137]
   [clojure.core$apply invokeStatic "core.clj" 667]
   [clojure.core$require invokeStatic "core.clj" 6007]
   [clojure.core$require doInvoke "core.clj" 6007]
   [clojure.lang.RestFn invoke "RestFn.java" 512]
   [lambdaisland.deep_diff2.diff_test$eval4071$loading__6721__auto____4072
    invoke
    "diff_test.cljc"
    1]
   [lambdaisland.deep_diff2.diff_test$eval4071
    invokeStatic
    "diff_test.cljc"
    1]
   [lambdaisland.deep_diff2.diff_test$eval4071
    invoke
    "diff_test.cljc"
    1]
   [clojure.lang.Compiler eval "Compiler.java" 7177]
   [clojure.lang.Compiler eval "Compiler.java" 7166]
   [clojure.lang.Compiler load "Compiler.java" 7636]
   [clojure.lang.RT loadResourceScript "RT.java" 381]
   [clojure.lang.RT loadResourceScript "RT.java" 372]
   [clojure.lang.RT load "RT.java" 459]
   [clojure.lang.RT load "RT.java" 424]
   [clojure.core$load$fn__6839 invoke "core.clj" 6126]
   [clojure.core$load invokeStatic "core.clj" 6125]
   [clojure.core$load doInvoke "core.clj" 6109]
   [clojure.lang.RestFn invoke "RestFn.java" 408]
   [clojure.core$load_one invokeStatic "core.clj" 5908]
   [clojure.core$load_one invoke "core.clj" 5903]
   [clojure.core$load_lib$fn__6780 invoke "core.clj" 5948]
   [clojure.core$load_lib invokeStatic "core.clj" 5947]
   [clojure.core$load_lib doInvoke "core.clj" 5928]
   [clojure.lang.RestFn applyTo "RestFn.java" 142]
   [clojure.core$apply invokeStatic "core.clj" 667]
   [clojure.core$load_libs invokeStatic "core.clj" 5985]
   [clojure.core$load_libs doInvoke "core.clj" 5969]
   [clojure.lang.RestFn applyTo "RestFn.java" 137]
   [clojure.core$apply invokeStatic "core.clj" 667]
   [clojure.core$require invokeStatic "core.clj" 6007]
   [clojure.core$require doInvoke "core.clj" 6007]
   [clojure.lang.RestFn invoke "RestFn.java" 408]
   [cljdoc_analyzer.metagetta.clojure$read_ns$fn__1615
    invoke
    "clojure.clj"
    101]
   [cljdoc_analyzer.metagetta.clojure$read_ns
    invokeStatic
    "clojure.clj"
    100]
   [cljdoc_analyzer.metagetta.clojure$read_ns invoke "clojure.clj" 95]
   [cljdoc_analyzer.metagetta.clojure$read_namespaces$fn__1628
    invoke
    "clojure.clj"
    167]
   [clojure.core$map$fn__5866 invoke "core.clj" 2755]
   [clojure.lang.LazySeq sval "LazySeq.java" 42]
   [clojure.lang.LazySeq seq "LazySeq.java" 51]
   [clojure.lang.Cons next "Cons.java" 39]
   [clojure.lang.RT boundedLength "RT.java" 1792]
   [clojure.lang.RestFn applyTo "RestFn.java" 130]
   [clojure.core$apply invokeStatic "core.clj" 665]
   [clojure.core$mapcat invokeStatic "core.clj" 2783]
   [clojure.core$mapcat doInvoke "core.clj" 2783]
   [clojure.lang.RestFn invoke "RestFn.java" 423]
   [cljdoc_analyzer.metagetta.clojure$read_namespaces
    invokeStatic
    "clojure.clj"
    167]
   [cljdoc_analyzer.metagetta.clojure$read_namespaces
    invoke
    "clojure.clj"
    131]
   [cljdoc_analyzer.metagetta.main$read_namespaces
    invokeStatic
    "main.clj"
    72]
   [cljdoc_analyzer.metagetta.main$read_namespaces
    invoke
    "main.clj"
    68]
   [cljdoc_analyzer.metagetta.main$get_metadata$fn__1786
    invoke
    "main.clj"
    103]
   [clojure.core$mapv$fn__8445 invoke "core.clj" 6912]
   [clojure.lang.ArraySeq reduce "ArraySeq.java" 111]
   [clojure.core$reduce invokeStatic "core.clj" 6827]
   [clojure.core$mapv invokeStatic "core.clj" 6903]
   [clojure.core$mapv invoke "core.clj" 6903]
   [cljdoc_analyzer.metagetta.main$get_metadata
    invokeStatic
    "main.clj"
    100]
   [cljdoc_analyzer.metagetta.main$get_metadata invoke "main.clj" 86]
   [cljdoc_analyzer.metagetta.main$_main invokeStatic "main.clj" 134]
   [cljdoc_analyzer.metagetta.main$_main invoke "main.clj" 109]
   [clojure.lang.AFn applyToHelper "AFn.java" 154]
   [clojure.lang.AFn applyTo "AFn.java" 144]
   [clojure.lang.Var applyTo "Var.java" 705]
   [clojure.core$apply invokeStatic "core.clj" 665]
   [clojure.main$main_opt invokeStatic "main.clj" 514]
   [clojure.main$main_opt invoke "main.clj" 510]
   [clojure.main$main invokeStatic "main.clj" 664]
   [clojure.main$main doInvoke "main.clj" 616]
   [clojure.lang.RestFn applyTo "RestFn.java" 137]
   [clojure.lang.Var applyTo "Var.java" 705]
   [clojure.main main "main.java" 40]],
  :cause
  "Could not locate clojure/test/check__init.class, clojure/test/check.clj or clojure/test/check.cljc on classpath."}}

Execution error (FileNotFoundException) at lambdaisland.deep-diff2.diff-test/eval4071$loading (diff_test.cljc:1).
Could not locate clojure/test/check__init.class, clojure/test/check.clj or clojure/test/check.cljc on classpath.

Diagnosis

If I list the jar contents:

$ jar tf ~/.m2/repository/lambdaisland/deep-diff2/2.2.124/deep-diff2-2.2.124.jar

META-INF/MANIFEST.MF
META-INF/
lambdaisland/
lambdaisland/deep_diff2/
lambdaisland/deep_diff2/puget/
lambdaisland/deep_diff2/puget/color/
META-INF/maven/
META-INF/maven/lambdaisland/
META-INF/maven/lambdaisland/deep-diff2/
lambdaisland/deep_diff2_test.cljc
lambdaisland/deep_diff2/printer_impl.cljc
lambdaisland/deep_diff2/printer_test.cljc
lambdaisland/deep_diff2/diff_impl.cljc
lambdaisland/deep_diff2/puget_test.cljc
lambdaisland/deep_diff2/puget/dispatch.cljc
lambdaisland/deep_diff2/puget/color/ansi.cljc
lambdaisland/deep_diff2/puget/color/html.cljc
lambdaisland/deep_diff2/puget/printer.cljc
lambdaisland/deep_diff2/puget/color.cljc
lambdaisland/deep_diff2/diff_test.cljc
lambdaisland/deep_diff2.cljc
META-INF/maven/lambdaisland/deep-diff2/pom.xml
META-INF/maven/lambdaisland/deep-diff2/pom.properties

we can see all test sources are included (ex. deep_diff2_test.cljc) - most likely not on purpose.

When cljdoc tries to analyze the jar, the test libs the test sources depend on aren’t included as deps for the jar therefore they won’t be found and… then analysis fails.

I'm not sure how the release jar is built, but the pom.xml currently includes the test dir which might be the causing those test sources to be included.

lread commented 2 years ago

(Thanks to @NoahTheDuke for raising the failure on Slack #cljdoc!)

alysbrooks commented 2 years ago

Thanks for the detailed writeup/investigation! (And thanks to @NoahTheDuke!) Yes, we like to keep the Cljdoc build green, since the only other source of API documentation is the source code itself. I've fixed similar issues with Lambda Island libraries and Cljdoc before—if I remember correctly, it's just a matter of excluding "test" from the main list of source directories and moving it to the appropriate alias (:test in this case).

lread commented 2 years ago

Hiya @alysbrooks! It all depends on what decides what goes in the release jar.

plexus commented 2 years ago

Looking at the deps.edn I agree "test" should not be in the top level paths, not sure why it ended up in there. There's no reason to bundle tests in the release jar, they blow up the size of the artifact for no apparent benefit.

So I think moving "test" to the :test alias is the right thing to do here. Note that we also have a mechanism in our tooling for dealing with optional dependencies, which is mainly there to appease cljdoc. E.g. if you look at cljbox2d its bin/proj looks like this

#!/usr/bin/env bb

(ns proj (:require [lioss.main :as lioss]))

(lioss/main
 {:license                   :mpl
  :inception-year            2021
  :description               "Clojure/ClojureScript wrapper for the Box2D physics engine"
  :group-id                  "com.lambdaisland"
  :aliases-as-scope-provided [:quil4 :clojure2d :testbed]})

Those :aliases-as-scope-provided are deps.edn aliases whose :extra-deps end up in the pom.xml with <scope>provided</scope>. This means they won't be transitively installed when depending on this library, but cljdoc will pick them up. Just pointing that out if other cases like this pop up.

alysbrooks commented 2 years ago

You can read the latest documentation here: https://cljdoc.org/d/lambdaisland/deep-diff2/2.3.127/doc/readme.