Welcome! Please see the About page for a little more info on how this works.

+2 votes
in tools.deps by

I've got a used case for an offline clojure project. I'd like to include a bundled dependency (in this case a version of Oz that I've modified to work offline so it won't fetch js dependencies). The result is an uberjar with all of the stuff Oz requires. I'd like to mess with it from the clj CLI tooling. I followed the prescription from the guide and have a minimal deps.edn co-located with with the uberjar:

{:deps {metasoarous/oz {:local/root "./oz.jar"}}}

In my mind, this should be (more or less) equivalent to invoking
java -cp oz.jar clojure.main

Without any additional changes to deps.edn, launching clj will then try to resolve deps (e.g. for clojurescript), which I don't want (in fact, they'll fail due to network settings).

Is there a prescribed way to just treat the uberjar as a dumb local dependency, without engaging the higher order dependency resolution machinery? I'd like to leverage the options in deps.edn (e.g. setting up source paths, etc), just with a bunch of libs pre-loaded in the uber.jar (assumably all dependencies I'd need in a limited environment).

Another option (I guess) would be to install it into the local .m2 and treat it as a maven coordinate, which should (hopefully) prevent clj from trying to sniff dependencies online.
I'd hope the local jar approach could be made to work though.

1 Answer

+1 vote

There currently is no "offline" mode for clj, and jar deps are examined, the pom found inside the jar, and dependencies retrieved based on that. I suppose if you produced an uberjar without an internal pom, that might be sufficient.

Why don't you really just do java -cp oz.jar clojure.main? clj is literally providing no value over the top of that in this scenario afaict.

edited by
I hoped the theoretical value would be classpath management, scripting, etc.  Managing source paths, leveraging aliases, etc.  Basically the minimal path and (non-maven) dependency setup stuff (like local file dependencies, git dependencies, etc.).  I will revert to manual path and dependency  management + scripts.
If you’re using an uberjar then none of those features apply?
edited by
The stuff not in the uberjar would definitely apply.  File deps, git stuff, aliases.  Also not requiring any internet connectivity, but possibly linked via local resolution on a relatively isolated box.  Uberjar just makes it both simple and local to truck dependencies for oz around onto a local machine.  I used to do this with lein offline, and it was okay (still a bit clumsy).  clj seemed like a better solution at the time, rather than duct taping class path generation, file deps, local jars,  and optional loads together with scripts and various load-file webs.  Kind of thought tools.deps could simplify things.
Once things are combined in an uberjar, tools.deps can no longer do anything useful with them - it just looks like one big artifact. Version selection doesn’t work, combining stuff on the classpath doesn’t work, etc. Aliases are for modifying dep resolution or classpath construction, but those are all broken by uberjars. The whole point of an uberjar is that there is no other stuff. Uberjars are inherently at odds with all dep resolution and classpath tools and should only be used when building a final application jar for deployment (and never put in Maven).
So the alternative (which I've done with lein) is to maintain a local .m2 prefilled (say from the originating machine) with all the dependencies, and pull that down onto the isolated box.  Then let the normal dependency resolution machinery kick off, rather than including a bulk set of pre-resolved dependencies by way of an opaque uberjar.  It's just moving the air around in the balloon - instead of packing a single uberjar, you pack a single .m2 archive, and conform to tools.deps expectations.  Or, install the uberjar itself as a local artifact in .m2 and point deps at that (perhaps unsavory).  So long as I stay within the universe of pre-existing dependencies in the local .m2, or relegate to projects to solely use [local libraries](https://clojure.org/guides/deps_and_cli#_using_local_libraries),  tools.deps should effectively work in offline mode since it resolves from the cache first, correct?  There shouldn't be anything forcing deps to try to connect to clojars or maven, right?
It sounds like you don't have an uberjar maybe? If you did, wouldn't everything be in the jar already? So it wouldn't try to pull in anything missing?