This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-10-29
Channels
- # 100-days-of-code (2)
- # bangalore-clj (1)
- # beginners (141)
- # cider (33)
- # cljs-dev (13)
- # cljsjs (7)
- # cljsrn (1)
- # clojure (88)
- # clojure-conj (3)
- # clojure-dev (24)
- # clojure-italy (11)
- # clojure-nl (4)
- # clojure-russia (1)
- # clojure-sanfrancisco (1)
- # clojure-spec (4)
- # clojure-uk (53)
- # clojurescript (65)
- # core-logic (2)
- # cursive (28)
- # datomic (33)
- # duct (2)
- # emacs (3)
- # figwheel-main (9)
- # fulcro (44)
- # hoplon (6)
- # leiningen (144)
- # mount (1)
- # nrepl (21)
- # off-topic (102)
- # onyx (2)
- # other-languages (5)
- # pathom (6)
- # planck (3)
- # portkey (1)
- # re-frame (7)
- # reagent (5)
- # reitit (17)
- # shadow-cljs (24)
- # spacemacs (16)
- # tools-deps (64)
- # uncomplicate (2)
- # vim (22)
So after a lot more experimentation with classifiers, dynamic version strings, etc., it looks like the only way I'm going to be able to achieve what I'm after (single project.clj
that can emit two different, JVM-specific artifacts that have different upstream dependencies, depending on which JVM the build is run on) is by twizzling the project name component in the defproject
form. e.g.
(def project-name (... logic that calculates a project name based on the JDK we're running on ...))
(defproject project-name "0.1.0-SNAPSHOT" ...)
But I've been unable to get that to work. Any tips, tricks or pointers?Maybe you can write a macro that takes the project-name as arg, and returns the defproject form you want?
although that may run into problems with the fact that you want to calculate the project name at run time, not compile time.
Possibly-effective hack: shell/clj/Python/etc. script that writes the project.clj file and does build/deploy/whatever commands, then tweaks the project.clj file and repeats.
@deactivateduser10790 I thought you were going with a version string change? at this point, the best I can think of is similar to what @andy.fingerhut mentioned concerning having an external script that picks the different jvm’s for you to run lein with, so a defproject
setup similar to this
@andy.fingerhut yeah that thought crossed my mind too, but it felt to me like a bridge too far - like I'm definitely headed down a bad path. 😉
@mikerod it turns out that when you use a version number suffix, the Maven machinery still only has a single POM file, and I need two (recall that my upstream dependencies differ, depending on which JVM is in use).
The a script could run it like
# jvm x
LEIN_JAVA_CMD=jvm-x-path lein <task>
# jvm y
LEIN_JAVA_CMD=jvm-y-path lein <task>
Sure, but I can't make assumptions about which JVM(s) consumers of the library are using.
This is a general purpose library that (hopefully!) many other folks will consume and enjoy. 😉
So I can't just assume they have the same JVMs installed that I do, let alone in the same locations.
Basically it's all fallout from Oracle's "project jigsaw". And it's a huge pain that I'd rather not have to deal with...
a consumer wouldn’t write anything, it’d just build with whatevr jvm they have lein using
They wouldn't.
But they do need to select which "edition" of my library they wish to consume, to ensure they get the correct upstream dependencies.
So yeah, you use this, and deploy artifacts of the form:
org.mine/some-project 0.1.0-SNAPSHOT-jdk8
org.mine/some-project 0.1.0-SNAPSHOT-jdk10
You can, but those share a pom.
I tested that first, as we discussed last week.
Nope that's not how Maven / Clojars work.
The second build overwrites the pom of the first.
I can't use classifiers, since I need to build on different JVMs.
And leiningen can't "split" classifiers to run on different JVMs.
but that doesn’t align with what you showed from google doing a similarly hacky classifier deployment based on versions
Recall that my dependencies are either included in the JVM (for JVM versions 1.7u6 through 10) or need to be explicitly pulled down (JVM v11+).
So I need two poms./
completely compile-time built-in due to the eval-syntax of the defproject based on lein jvm
At at the risk of sounding like a broken record, upon deployment to clojars, LEIN_JAVA_CMD=jvm-y-path lein <task>
overwrites the POM file that was previously generated by LEIN_JAVA_CMD=jvm-x-path lein <task>
.
So I end up with 1 pom and 2 jars, which is exactly the opposite of what I need.
I confirmed it.
I thought as you did, until I tried it out.
And it didn't work.
if you use classifiers - they need to deploy at the same time, because you can’t “overwrite” releases
I can't use classifiers.
Each pom has to be built on a different JVM version, or else the unit tests won't pass.
If you build one JAR, overwriting pom file, and deploy (in the script), then start over with a different JVM version, it shouldn't matter that the pom file gets overwritten after the deploy?
The poms are different.
@mikerod I did exactly that. Perhaps I'm not explaining myself very clearly, but Maven / Clojars elide the "qualifier" on the end of the version string.
So you end up with two poms that "land" in the same directory + file on Clojars.
If you can find any way to do what you want via a sequence of commands from an interactive shell, that produces the correct results, script that.
if it deployed as a real classifier then you couldn’t deploy 2 separate times to the same coordinate
i.e. the second overwrites the first.
@mikerod I can't use classifiers.
the maven definition of a classifier has some vague semantics around final repo structure
I need each "build" to use a specific JVM version, and classifiers can't be specified to use a particular JVM.
(since leiningen itself is running within a JVM - it can't swap that out at runtime).
you showed me some google repo, that used a “classifier version” structure, but it was actually imposed on the directory structure itself - so it sort of “wasn’t a classifier”, but could be used like one as a mvn coordinate
Correct - to get that out of a single project.clj
I need to change the project name.
Hence my question this morning.
If the project name were a string (as the version is) this would be trivial.
But it's not - it's a symbol.
Yep - that's the only way to influence how Leiningen's underlying Maven machinery determines where to write files during deployment.
Do you have a manual sequence of steps you know how to follow that produces the results you want?
or if you don’t care about version that much, could just pick a naming scheme that doesn’t cause it to “look like a classifier”
Outside of leiningen, you mean?
even if that sequence of steps involves hand-editing the project.clj and/or other files?
Let me pseudo code it...
Make a script that does those steps, with instead of "hand-edting one or more files" does sed
or any other program to edit those files that you can think of.
1. Select Oracle JVM v1.8 (there are a million ways to do do this, all of them unpleasant) 2. Run unit tests, without the additional dependencies (`lein test`) 3. Build JAR and deploy, without the additional dependencies (`lein deploy clojars`), ensuring the deployed artifacts (BOTH JAR AND POM) have unique GAV coordinates 4. Select Open JDK v11 (there are a million ways to do do this, all of them unpleasant) 5. Run unit tests, with additional dependencies (`lein with-profile +openjfx11 test`) 6. Build JAR and deploy, with additional dependencies (`lein with-profile +openjfx11 deploy clojars`), ensuring the deployed artifacts (BOTH JAR AND POM) have unique GAV coordinates
Could be bash, could be Python, clj, etc. Whatever you are most familiar and comfortable with maintaining.
I don't even need to see what the other steps are, literally. If you can write them as commands in a bash script, Bob's your uncle.
If there are any steps that you don't know how to write as a command in a bash script, please ask -- we can probably figure out a way to do it.
What about my fellow library developers on Windows?
Sorry - that was a mostly rhetorical question.
@deactivateduser10790 who all is building this?
if you need windows support also, for building, then yes, things get more complicated with scripts hah
Yes scripting is always a back door way out. But it's a pretty sucky one imho.
I’ll probably bow-out of trying to fix this issue, since I don’t feel like I’m adding value at this point 😛
so you could conditional logic, based on jvm or something, the project name if you wanted to
@mikerod that doesn't work:
(def project-name "foo")
(defproject #=(symbol project-name) "0.1.0-SNAPSHOT"
$ lein jar
Created [snip]/target/project-name-0.1.0-SNAPSHOT.jar
(and yes I guess I could put a mound of logic inside the call to symbol
, but that gets pretty messy)
(defn project-name [] (symbol "foo"))
(defproject #=(project-name) "0.1.0-SNAPSHOT" ...)
That worked - thanks @mikerod. Next hurdle: https://github.com/technomancy/leiningen/issues/2473
@deactivateduser10790 you tried :leaky
metadata on the profile too?
but that is sort of counterintuitive to me how with-profile
can be ignored when not :leaky
. That may be by design, not sure.
^:leaky
was the missing piece - thanks @mikerod !
I think lein v3 is even opting to always only go with #=
reader dispatch macro instead of the classically used ~
, but I have no more details on that. It’s just in a comment I see in the source - https://github.com/technomancy/leiningen/blob/7357010431c926abb559d55b295fe1ba7791ed20/leiningen-core/src/leiningen/core/project.clj#L198
You could write a PowerShell script if you were so inclined (or had a colleague who is)
At times, I consider scripting the unequivocal front door 🙂
There's also LSW
Going off on a tangent for a moment, are there any thoughts around revisiting build tools, especially in light of clojure/tools.deps
?
I think the idea of tools.deps is cool that it tried to focus on one small part of what build tools bundle in most of the time - dep mgmt
however, eventually you have to compose a bunch of parts together either yourself via scripts, or a build tool that tries to be all in one
I’m not sure where the tools.deps idea is headed beyond tools.deps itself, but already, looks to be a script-centric view of doing things when I read how people are using it in their stack
I think integrating it with lein and removing that “classpath” part is at least cool/interesting
in terms of revisiting build tools overall, when it comes to complicated build and deployment setup, I’m not sure there is an easy answer for build tools. It seems that many exists and everyone is always unhappy with them all eventually 😛
Definitely -- I see it discussed on the #tools-deps channel, and someone there has been publishing and perhaps maintaining a list of tools.deps based tools
I haven't used them myself, so can't help you with what exists vs. what hasn't been developed yet.
FWIW I've played with the lein-tools-deps
plugin, and it's fine as far as it goes. The issue comes in that most other leiningen plugins can't use deps expressed in deps.edn
.
So stalwarts like lein-ancient
become useless, which is a big loss.
I guess I'm just wondering if the consolidation of dependency management by the core Clojure team will sufficiently break the existing build tools that it's a logical point to re-evaluate build tools more generally...
By 'break existing build tools' you mean because some project you want to build via Leiningen doesn't come with a project.clj file? I don't understand "break" there.
I mean "break" in the sense of "these tools can't directly consume deps.edn
files yet, and it seems like a substantial effort to add support for that and deprecate their own native dependency management mechanisms (given the ripple effect through the plugin ecosystem etc.)".
Sure, but it is "opt-in" breakage, e.g. moving from major version 1 to version 2 on your own time frame (or not)
Leiningen-specific plans for supporting tools.deps seems best discussed here, but at least lein ancient
has a tools.deps-based replacement someone has already developed: https://github.com/RickMoynihan/lein-tools-deps/issues/63