This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
How do I tell my uberjar where/how to find the resources
directory if I'm using lein uberjar
to create it?
Do you mean, you can unzip the uberjar and spot the contents of your resources directory somewhere inside it, but you wonder how your program can find them? Or do you mean you can unzip the uberjar and you don't see the contents of your resources directory anywhere among the contents of the uberjar?
I've done a bit of searching since asking. I have a folder of game data called resources
I need to access. When I do lein run or lein repl, my code can reference files inside the directory contents, but I don't know how to do that in the uberjar.
The key is that from the point of view of a running program, resources must not be treated as a directory. Its contents can be accessed via Java's getResourceAsStream or Clojure's resource function (https://clojure.github.io/clojure/clojure.java.io-api.html#clojure.java.io/resource).
The most charitable view of this quirk of Java's design is that your running program (edit: running from a jar, I mean) can't access "src" either.
So if I've got ~9000 files in there, am I going to need to call (io/resource "filename")
for every one?
Yup. If that's not pleasant then resources isn't a good place for such stuff OR you could store a "zip" as the resource, open the "zip" once, and cruise around it using java.util.zip.
So where should it be if it isn't in resources? Just trying to figure out how this work in Java. I'd like to do this something like how this project does it: https://github.com/MegaMek/megamek/tree/master
But it's a huge project, I can't figure out where to begin looking to find how they load their resources.
to the initial question, lein uses :resource-paths
with a vector containing zero or more relative paths to resource directories
When you run an uberjar, the classpath is just that JAR file so you can treat it as a file and use java.util.jar.*
classes and functions to walk through the entries in that JAR file looking for the files you want.
For example, at work we have a migration
uberjar that has SQL migrations in .sql
files in a resources
folder in the source project. We use a "unique" pattern for the paths to those SQL so we can regex-match them when we walk the entries in the JAR file, and that gives us a list of relative paths (from the classpath root) which we can then pass to io/resource
when we need to read them.
(let [cp (System/getProperty "java.class.path")
jar (java.io.File. cp)]
(if (and jar (.exists jar))
(let [jis (java.util.jar.JarInputStream. (java.io.FileInputStream. jar))
files (loop [entry (.getNextJarEntry jis) matches #{}]
(if-not entry
(sort matches)
(recur (.getNextJarEntry jis)
(if-let [match (re-find matching-pattern (.getName entry))]
(conj matches match)
matches))))]
(do-stuff-to files))
(throw (ex-info "Unable to find JAR file" {:cp cp}))))
is there any example of loading jar from local machine in project.clj file ?
Haven't tried it lately, but did you find https://stackoverflow.com/questions/2404426/leiningen-how-to-add-dependencies-for-local-jars ?