depstar

Discussion around https://github.com/seancorfield/depstar
Eric Ihli 2020-10-28T17:27:40.087900Z

Built an uberjar with clj -A:depstar -m hf.depstar.uberjar prhyme.jar Library has the following line: (nippy/thaw-from-file (io/resource "dark-corpus-2.bin")) File confirmed in jar with jar ft prhyme.jar | grep dark-corpus-2.bin jar depended on by another project with {:local/root "/home/user/code/prhyme/prhyme.jar"} Error thrown when starting a repl:

Caused by: java.lang.IllegalArgumentException: Not a file: jar:file:/home/user/code/prhyme/prhyme.jar!/dark-corpus-2.bin
	at <http://clojure.java.io|clojure.java.io>$fn__11362.invokeStatic(io.clj:61)
Any thoughts on what would cause this? Is that ! in jar:file:/home/.../prhyme.jar!/dark-corpus-2.edn relevant? Or is it some artifact of an internal of java loading resources? I see a sorta similar issue at https://github.com/seancorfield/depstar/issues/27 but that person was getting an error about a file being skipped. Not the case for me. resources is on the path in deps.edn.

Eric Ihli 2020-10-28T17:30:19.088200Z

I may have just answered my own question. I see there is a difference between an io/resource and an io/file.

(= (io/file (io/resource "dark-corpus-2.bin"))
;; =&gt; #object[java.io.File 0x4f44ce9c "/home/user/code/prhyme/resources/dark-corpus-2.bin"]   
   (io/resource "dark-corpus-2.bin")
   ;; =&gt; #object[java.net.URL 0x31865f0d "file:/home/user/code/prhyme/resources/dark-corpus-2.bin"]
   )

Eric Ihli 2020-10-28T17:35:23.088400Z

Nope. Same thing.

Eric Ihli 2020-10-28T17:39:36.088600Z

Or I was close... https://groups.google.com/g/clojure/c/8scFidro4ow > Just delete that line. The io/resource function returns a URL which all the Clojure IO functions can handle just fine-as is. When running in development the URL happens to be a file:// URL, and thus something io/file can handle. Once the resource is in a JAR that is no longer the case, and hence exceptions. Just don't require a file when any URL will do and you'll be fine. But nippy's thaw-from-file sends it back to an io/file.

(defn thaw-from-file
  "Convenience util: like `thaw`, but reads from `(<http://clojure.java.io/file|clojure.java.io/file> &lt;file&gt;)`.

  To thaw from a resource on classpath (e.g in Leiningen `resources` dir):
    (thaw-from-file (<http://clojure.java.io/resource|clojure.java.io/resource> \"my-resource-name.npy\"))

  See also `freeze-to-file`."
  ([file          ] (thaw-from-file file nil))
  ([file thaw-opts]
   (let [file (jio/file file),
         ba (byte-array (.length file))]
     (with-open [in (DataInputStream. (jio/input-stream file))]
       (.readFully in ba))

     (thaw ba thaw-opts))))

seancorfield 2020-10-28T17:54:25.089700Z

@ericihli Have you confirmed that file is actually in the JAR? jar tvf prhyme.jar | fgrep dark-corpus

seancorfield 2020-10-28T17:56:53.090400Z

Also, if you build the jar like this, you'll see it tell you every file it puts into the JAR: clj -A:depstar -m hf.depstar.uberjar prhyme.jar -v

Eric Ihli 2020-10-28T18:42:12.090500Z

Yeah, it's definitely in there. I'm pretty sure now this issue has nothing to do with depstar. https://groups.google.com/g/clojure/c/8scFidro4ow I'm gathering you can't use io/file to access a packaged resource. Nippy is using io/file to get the length of the file to create a byte-array.

(defn thaw-from-file
  "Convenience util: like `thaw`, but reads from `(<http://clojure.java.io/file|clojure.java.io/file> &lt;file&gt;)`.

  To thaw from a resource on classpath (e.g in Leiningen `resources` dir):
    (thaw-from-file (<http://clojure.java.io/resource|clojure.java.io/resource> \"my-resource-name.npy\"))

  See also `freeze-to-file`."
  ([file          ] (thaw-from-file file nil))
  ([file thaw-opts]
   (let [file (jio/file file),
         ba (byte-array (.length file))]
     (with-open [in (DataInputStream. (jio/input-stream file))]
       (.readFully in ba))

     (thaw ba thaw-opts))))
I'm trying an alternative.
(defn thaw-from-file
  ([file          ] (thaw-from-file file nil))
  ([file thaw-opts]
   (let [xin (io/input-stream file)
         xout (ByteArrayOutputStream.)]
     (io/copy xin xout)
     (nippy/thaw (.toByteArray xout) thaw-opts))))
That does appear to fix it.

seancorfield 2020-10-28T18:48:36.090700Z

Interesting. Which line exactly throws the exception? Is it the .length call?

Eric Ihli 2020-10-28T18:51:09.090900Z

(jio/file file). Says it can't find it when file is (io/resource "some-resource")

Eric Ihli 2020-10-28T18:51:49.091100Z

Works fine until you package the code up as a jar and another package depends on it.

seancorfield 2020-10-28T19:16:18.091300Z

Ah, so the docstring is misleading then:

To thaw from a resource on classpath (e.g in Leiningen `resources` dir):
    (thaw-from-file (<http://clojure.java.io/resource|clojure.java.io/resource> \"my-resource-name.npy\"))

seancorfield 2020-10-28T19:16:49.091500Z

Well, glad you have it working now!

seancorfield 2020-10-28T19:18:04.091700Z

We used to use Nippy at work but it's a strange beast so we decided to switch to something else. In the end, I think we stopped using all the taoensso libraries.

Eric Ihli 2020-10-28T19:25:47.091900Z

Oh man that's interesting to hear. I've found myself migrating towards all of them.