This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-06-10
Channels
- # announcements (2)
- # asami (2)
- # babashka (29)
- # beginners (115)
- # cider (5)
- # clara (9)
- # cljdoc (14)
- # cljs-dev (1)
- # cljsrn (18)
- # clojars (3)
- # clojure (73)
- # clojure-australia (7)
- # clojure-europe (74)
- # clojure-nl (3)
- # clojure-norway (8)
- # clojure-spec (3)
- # clojure-uk (36)
- # clojured (1)
- # clojurescript (15)
- # conjure (18)
- # datomic (6)
- # deps-new (11)
- # depstar (7)
- # fulcro (2)
- # instaparse (1)
- # jobs (9)
- # nrepl (8)
- # off-topic (21)
- # pathom (5)
- # polylith (42)
- # proletarian (1)
- # rdf (10)
- # re-frame (2)
- # react (1)
- # reagent (20)
- # releases (3)
- # remote-jobs (4)
- # rum (9)
- # shadow-cljs (79)
- # sql (11)
- # tools-deps (64)
- # vim (3)
- # xtdb (26)
New prerelease of Clojure CLI 1.10.3.875:
• New: support for specifying multiple functions with -X with ->
semantics
• https://clojure.atlassian.net/browse/TDEPS-182 - Improve deprecation message to be more accurate
• https://clojure.atlassian.net/browse/TDEPS-183 - Fix -Sdescribe output to be valid edn on Windows
• https://clojure.atlassian.net/browse/TDEPS-179 - Fix incorrect classpath when :classpath-overrides removes path



We’ve simplified our CI build by using this to run multiple steps at once so it’s already a win for us — thank you!
Awesome! Can you point me to an example of how that new -X
stuff works? Is it literally just -X:myalias foo.bar/fn1 foo.bar/fn2 some.other/thing
and each should take a hash map and return a hash map?
What happens if any of them return nil
? Does exec just pass the original input hash map into the next function, or does it end up passing nil
?
well importantly, the first function gets the kvs from the exec-args/ cli
it's like ->, so if one function returns nil, the next gets nil
Ah, so that also means that the functions in the 2nd pos on don’t need to take hash maps, right? It could be any data produced from the earlier fns?
I suppose :)
I will not claim that this is fully baked yet, so I reserve the right to change my answer before it becomes a stable release :)
(I’m already imagining how folks like @borkdude might think of abusing this 🙂 )

repls are also very usable repls :)
> -X:myalias foo.bar/fn1 foo.bar/fn2 some.other/thing
how does it know that it's (-> {} foo.bar/fn1 foo.bar/fn2 some.other/thing)
and not (foo.bar/fn1 {'foo.bar/fn2 'some.other/thing})
?
@seancorfield could you help me understand how I could abuse this? ;)
symbols at the front are functions
fn* [kpath v]* map?
i was thinking about sci/bb but at that point you could just pass in forms to be evaled
ah, so clj-exec first consumes all symbol args as fn chain, and then rest args as map arg?
well we now have trailing map support ala 1.11 too
https://github.com/clojure/brew-install/blob/1.10.3/src/main/clojure/clojure/run/exec.clj#L100
to be more precise
parsing is done with that spec
but of course :)
thanks :)
I tried this:
clj -X clojure.core/pr-str clojure.core/read-string clojure.pprint/pprint :a 1
but when I was playing with it I felt the order is somewhat hard to follow, because arg-map is in the end, unlike in real ->
(defmacro <- [,,,],,,)
:grinning_face_with_one_large_and_one_small_eye:
interested in feedback, so do more , and come back
intuitively I wanted to write this:
clj -X clojure.pprint/pprint clojure.core/read-string clojure.core/pr-str :a 1
because arg-map is closer to fn that will receive it. e.g.
(clojure.pprint/pprint (clojure.core/read-string (clojure.core/pr-str {:a 1})))
I don't know that this is something you're going to want to use all the time, but it is another dimension of composition available
the goal is not to replicate the repl. if you want that, use a repl
I guess my big test is going to be breaking depstar
up into multiple -X
-compatible functions so you can run parts of it or all of it in a pipeline 🙂
if you do do that, I would be very interested in hearing your questions/feedback. if I may be so bold, that might be a better thing to do in design space before actually cutting the code :)
Oh, definitely. I need to tease apart the various useful processes that depstar
performs and figure out exactly what inputs and outputs each of them have.
I have smaller things to test it on before that 🙂
the key thing is that inputs/outputs need to align, which harkens to namespaced keys ... but those fight with conciseness of what you want at the CLI
Okay, another argument why (fn1 (fn2 argmap))
might make sense:
PS C:\Users\Vlaaad\Projects\deps-test\lib> Get-Content .\deps.edn
{:aliases {:deploy {:ns-default deploy}}}
PS C:\Users\Vlaaad\Projects\deps-test\lib> Get-Content .\src\deploy.clj
(ns deploy)
(defn dev [args]
(merge
{:env :dev
:url "dev-cluster"}
args))
(defn prod [args]
(merge
{:env :prod
:url "prod-cluster"}
args))
(defn deploy [env]
(prn :deploy env))
Suppose I want to deploy my app. Currently I have to use this order: dev deploy
PS C:\Users\Vlaaad\Projects\deps-test\lib> clj -X:deploy dev deploy :a 1
:deploy {:env :dev, :url "dev-cluster", :a 1}
But this is unintuitive, as I would expect the at the command line first specify an "action" and then "env"
PS C:\Users\Vlaaad\Projects\deps-test\lib> clj -X:deploy deploy dev :a 1
:deploy {:a 1}
but with ->
style the main action goes last instead of being firstI don’t understand this at all. ->
says “do things in this order” and that’s exactly what I would expect: setup the env, run the command.
agreed, the order is the most important thing here
> clojure -X:depstar sync-pom compile jar
If I wanted to add a prepare-assets
step? How would that fit in? Is it like writing any other clojure function, or would it be like writing a depstar plugin? How likely is it that an idiomatic clojure function would also function as a cli target?
One of the reasons automating git is a pain is that there 1) a low level programmatic library and 2) a high level command line interface and not much in between. Maybe there's no way around it, but it seems like it's easy to fall into the trap where the cli is the primary interface and the programmatic interface becomes less idiomatic. It's a tough problem to crack since the clojure cli wants to tame the bashisms, clojurisms, and javaisms with just the right isms on top.
I’ll try to choose the hash map contents/keys carefully but it would be just writing a function that took a hash map and return a hash map and then making sure it’s on the classpath. Some of it would depend on what inputs your prepare-assets
function needed?
I think having a task that computes the project basis (possible based on aliases provided as :exec-args
) and then passes that through the pipeline would be helpful.
I think we may all get a better sense of how this should work once we see tools.build
— I suspect it will have a few “utility” tasks that standardize some of this setup. @alexmiller has indicate that tools.build
will have a number of “standard” build steps built-in so it’ll be a case of other tools following that lead and building on the basic pipeline.
depstar
does a lot of “smart” stuff when building uberjar files (in terms of merging things) so once I have tools.build
to play with, I’ll figure out how to make the “smart” part of depstar
replace the (presumably, much simpler) uber
/`jar` tasks.
There will be a basis building function. Well, there are multiple atm, I’m trying to sort all that out :)
@alexmiller What’s the thinking around -X
functions that would require (shutdown-agents)
calls at the end to avoid the 60 second “hang”? That’s been a long-standing issue with -main
functions. I didn’t check the latest exec source but does it handle that? (since you clearly cannot chain exec functions that call shutdown-agents
)
Haven’t thought about it
I just looked at the exec.clj
code and it does not call (*exit* 0)
or (shutdown-agents)
in the “happy” case…
Yeah, my first test of chaining tasks leads to a 60 second hang at the end because of that.
(I used to run the tasks individually and they had calls to (shutdown-agents)
at the end — which I removed so I could chain them — and I can’t just call clojure.core/shutdown-agents
via -X
because it takes no arguments 😞
Yeah, we should probably do that for you
Thank you, yeah, that would be super-helpful!
We’ve simplified our CI build by using this to run multiple steps at once so it’s already a win for us — thank you!