Fork me on GitHub

Ran into an interesting issue while working on depstar 2.0 today: I'd been assuming that you could use :replace-deps to add it as a dependency now that it calculates the project basis from the deps.edn files (and the :aliases you provide it with), and that works great for almost everything... except where it does AOT compilation, which has to be done in the context of the project's code so that the necessary dependencies are available. I looked at what Leiningen does and it seems to set up a specific classloader context for running compilation (based on the project's dependencies etc).


Although calculating the project basis causes all the project's dependencies to become available (locally) for inclusion in the uberjar, they are not on the classpath used to invoke depstar if :replace-deps is used.


Thoughts/suggestions? What I've done for the time being is just documented that if you ask depstar to do AOT-compilation, you'll need to use :extra-deps instead of :replace-deps when specifying it as a dependency. What options do I have if I wanted to run clojure.core/compile in a different classloader context?


(that's not ideal because then you run the risk of depstar's transitive dependencies affecting your project's compiled code in some way)


start another JVM just for the compilation from within depstar


that’s the approach I’m taking on a similar tool


@ghadi Seems like a bit of a sledgehammer to crack a nut but it is also straightforward I guess. Are you shelling out? If so, how do you decide what command to use? Or is there a JVM-specific spawning process?


Hmm, with ProcessBuildler, that's not bad. And it can generally assume java -cp ... will work I guess?

Alex Miller (Clojure team)04:12:17

Separate JVM is what I did in tools build

Alex Miller (Clojure team)04:12:49

You can’t run clj if java doesn’t work so ...


And the clojure script sets JAVA_CMD so I can rely on that too.


Here's what I ended up with (it's all due for a big refactor -- most of today has been focused on just getting all the 2.0 functionality working and the next job is creating automated tests and then refactoring)


I see the output of -Stree has changed with the latest cli version. Are there some docs on what the notation used means?


@kenny X means that version of the dependency is not being used. The keywords at the end of some lines indicate why a particular version was used or not.


X means it's not being used because it's overridden by something else? It seems that last keyword is only every present on X's.


Example from one of our services:

X compojure/compojure 1.6.2 :use-top
    X ring/ring-core 1.6.3 :older-version
      X ring/ring-core 1.6.0 :older-version
      X ring/ring-core 1.6.0 :older-version
    X ring/ring-core 1.7.1 :older-version
  X worldsingles/lowlevel /Developer/workspace/wsmain/clojure/lowlevel :use-top
    . ring/ring-core 1.8.2 :newer-version
        X org.clojure/java.classpath 0.3.0 :older-version
Ring 1.8.2 is the :newer-version that is selected in preference to 1.6.3 which is :older-version, and Compojure 1.6.2 was specified as a top-level dependency (overriding any transient dependency on it).


Oh I see. What does it mean when a dep doesn't have a keyword?


That's just a normal selection of the version.


As in all deps have the same version of the dep?


The end result is just one set of versions. If there's no conflict of versions, there will be no annotation I believe.


Right. That's what I'm seeing. Just making sure it was the correct interpretation. This new output is great. How come it isn't documented anywhere? Alpha?



X org.clojure/java.classpath 0.3.0 :older-version
    . org.clojure/java.classpath 1.0.0
In this case 1.0.0 was selected implicitly (it's only a transitive dep in our code), and the older version was excluded because a newer version had already been found.


I expect @alexmiller can provide more detail when he's around...

Alex Miller (Clojure team)18:12:03

It’s a bit more complicated than that, and there are some cases where inclusions list a reason too

Alex Miller (Clojure team)18:12:14

Maybe I will doc it today :)

Alex Miller (Clojure team)18:12:52

I omit it in cases where it’s uninteresting

Alex Miller (Clojure team)18:12:44

Or finding same dep version already selected


In that case, why wouldn't it be annotated with :newer-version like in your first example @seancorfield?


@kenny If it finds version N and later finds version N+1, I would expect it to annotate both, and then if it continues to find version N+1 it will not annotate those (since they are "finding dep version already selected")


If it only finds version N across all deps, it's not going to annotate either.


At least, that's my understanding of what @alexmiller just said.

Alex Miller (Clojure team)19:12:13

it doesn't annotate both because it's a single pass breadth-first expansion

Alex Miller (Clojure team)19:12:57

(or rather to be clear, all choices have a reason, I'm just suppressing some of them in the printing b/c they're not interesting)

Alex Miller (Clojure team)19:12:58

when we first see a lib (version N) during expansion, it will have reason :new-dep

Alex Miller (Clojure team)19:12:32

if you later find same lib version N+1, it will have reason :newer-version

Alex Miller (Clojure team)19:12:12

but there are a lot of tricky cases

Alex Miller (Clojure team)19:12:08

right now the reason codes :new-top-dep, :new-dep, and :same-version are suppressed


I'm getting a different resolution for a project that uses tools.reader 1.3.2 and pulls in a mvn lib that depends on tr 1.3.4 (I'm getting tools reader 1.3.4 in this case which I'm happy about), when using that lib via local/root (then it pulls in 1.3.2)


Is that expected?


(I did try -Sforce)


I will just remove the tools.reader dep from the project since I always want to use what the local/root project is using anyway

Alex Miller (Clojure team)19:12:40

not enough info there for me to tell

Alex Miller (Clojure team)19:12:00

local/root dep changes are not automatically picked up, so you do need to -Sforce if those change

Alex Miller (Clojure team)19:12:33

if you have an output from -Strace or -Stree, happy to take a look


oh yikes, I see what is happening. the mvn lib has AOT-ed class files... which should not happen.


Found the culprit: apparently when you have a :main in the top-level of defproject lein will compile on deploy ... which might make sense. I just used that main for testing some stuff. Problem solved.


How do you get to this page without the link?


It linked in two places on the deps/CLI reference page.


Ah. Isn't it odd how it's not in the left nav though?


It's not a reference in and of itself: it's just extra material for an existing reference. Not every page is directly linked in the left nav.


The deps/CLI reference page is the entry point. The new page is linked from dep expansion under the Resolve dependencies section of Operation and also from tree printing under Other Programs (for -X:deps tree).


Oh, okay. I could potentially see that being confusing for someone who is directly sent this link. That person has no way to "back out" to contextualize 🙂

Alex Miller (Clojure team)21:12:02

undoubtedly more to say, but that is a dump of several things have only been in my head for a long time so felt good to get them out :)


hi, what is the equivalent in deps.edn of :java-source-paths ["src/java/"] from leiningen ? I would like to add deps.end for clj-antlr so I can use it from git. The java directory contains java sources:


@eugen.stan no equivalent. You'll have to use javac yourself first.


thanks, I keep finding these edge cases 🙂 . Do you have any examples?


@eugen.stan He means you literally run the javac command yourself to compile the .java files to .class files.


This isn't an "edge case" -- this is just something that the Clojure CLI was not intended to do, by design. Leiningen is sort of a "kitchen sink": it has a whole bunch of tools included that have nothing to do with just "running Clojure code" (which is what the Clojure CLI is designed for).


People are building "tools" that mimic some of the stuff that Leiningen does (or that is provided by one of the many Leiningen plugins) and those "tools" are just small Clojure programs that you run via the Clojure CLI.


When you look at the general design principles behind Clojure -- and a lot of the things that Cognitect folks have produced -- there's a deliberate choice to keep things simple: each tool should do one job.


Someone could build a tool to compile Java source code -- a tool you could run from the Clojure CLI -- but you'd still need to run that tool and then run other tools and/or the CLI itself. There's still no "task pipeline" for the Clojure CLI. Maybe will provide that "task pipeline"? We'll have to wait and see what the Cognitect folks produce.