This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-03-26
Channels
- # announcements (9)
- # babashka (36)
- # beginners (13)
- # biff (24)
- # calva (12)
- # clj-kondo (18)
- # clojure (65)
- # clojure-brasil (1)
- # clojure-europe (11)
- # clojure-nl (1)
- # clojure-norway (87)
- # clojure-uk (4)
- # clojurescript (28)
- # datahike (25)
- # fulcro (12)
- # hyperfiddle (16)
- # malli (74)
- # missionary (1)
- # music (2)
- # off-topic (24)
- # polylith (4)
- # releases (3)
- # tools-deps (23)
Is this a bug or documentation error? The https://clojure.org/reference/clojure_cli#aliases says that :exec-args
specified in multiple aliases are combined with deep-merge, but the actual implementation does a regular merge:
https://github.com/clojure/tools.deps/blob/0774b8cc144a06f09c0ba4ec75e3d2adc55a04ba/src/main/clojure/clojure/tools/deps.clj#L169
I updated that section of doc recently, so that may be a doc error
Is there a case to be made though for actually deep-merging or concatenating values in the exec-args map? For context, I was looking at calling nrepl's main function using -X
instead of -M
, which lets me specify the middlewares in an regular EDN vector (instead of the awkward command-line string via :main-opts).
I was hoping that this could also compose with other aliases which add their own dependencies and nREPL middlewares, but there doesn't seem to be a clean way of doing so - eg. being able to call clojure -X:portal:nrepl
and having the :portal
alias somehow append the symbol portal.nrepl/wrap-portal
to the list of middlewares passed to :nrepl
's exec-fn.
could you share the example values you are trying to combine?
I'm imagining something like this, where running clojure -X:portal:cider
would pass a concatenated sequence of 3 elements as the :middleware arg.
{,,,
:aliases
{:portal {:extra-deps {djblue/portal {:mvn/version "0.53.0"}}
:exec-args {:middleware [portal.nrepl/wrap-portal]}}
:cider {:extra-deps {cider/cider-nrepl {:mvn/version "0.47.1"}
refactor-nrepl/refactor-nrepl {:mvn/version "3.9.1"}}
:exec-fn nrepl.cmdline/dispatch-commands
:exec-args {:port 2171
:middleware [cider.nrepl/cider-middleware
refactor-nrepl.middleware/wrap-refactor]}}}}
The sample configurations out there all use -M
options, where there's no way of composing arguments so one ends up with something like:
{,,,
:aliases
{:portal {:extra-deps {cider/cider-nrepl {:mvn/version "0.47.1"}
djblue/portal {:mvn/version "0.53.0"}}
:main-opts ["-m" "nrepl.cmdline" "--middleware"
"[cider.nrepl/cider-middleware,refactor-nrepl.middleware/wrap-refactor,portal.nrepl/wrap-portal]"]}
:cider {:extra-deps {cider/cider-nrepl {:mvn/version "0.47.1"}
refactor-nrepl/refactor-nrepl {:mvn/version "3.9.1"}}
:main-opts ["-m" "nrepl.cmdline" "--middleware"
"[cider.nrepl/cider-middleware,refactor-nrepl.middleware/wrap-refactor]"]}}}
but that's not even deep merge, that's something more
you're doing deep merge + vector concat
where do these magic semantics end?
Yeah, I realise it might be out of scope for tools.deps, maybe one would supply another key on the final alias specifying how to merge exec-arg values, like
{ :exec-args-merge-with {:middleware clojure.core/concat}}
I don't think I'm going to do that
try to unroll the need more - why not maps here? order I presume
this is a good example, feel free to put it on http://ask.clojure.org as a request. happy to collect votes and think about ideas
I'm not exactly sure if the order of nrepl middleware matters in practice, guess I was just looking for some sort of mechanism for composing aliases which 'depend' upon each other.
middleware generally stack so order is relevant
I am open to things that have more general semantics, there is already too much preciousness in these merge rules
really don't want to make anything less general than what's there now
yeah, the current UX of specifying these optional dependencies+middlewares via :main-opts
just results in combinatorial explosion since each one needs to be the final alias actually performing the call to clojure.main, I always found it quite unfriendly
I'll just chime in and say that I used to wish for this too -- specifically for merging/concat of the middleware argument(s) -- but in the end I wrote a little REPL-starter library and use that instead. It tests to see what is available on the classpath and dynamically builds the middleware vector based on that: https://github.com/seancorfield/dot-clojure/blob/develop/src/org/corfield/dev/repl.clj#L123-L132
I do think there's a gap in the -M
/ -X
stuff regarding "repeated" arguments -- tools.cli
supports arguments that can be repeated to produce a collection of values -- but I don't know how you could provide that in a sane way.
If -M
concatenated arguments, you could do basic repeated arguments but then you'd also lose other aspects of positionality (e.g., you couldn't rely on having a -m
argument in one alias that let you pass subsequent command-line arguments into that -main
function).
And -X
is map-based so you can't have repeated keys there that combined their arguments because you'd lose the ability to override arguments.
I don't know what the solution would look like.
I came up with an ad-hoc solution using namespaced keys to bypass the overriding merge semantics in :exec-args
, then relies on the exec-fn to combine them together with appropriate semantics.
https://gist.github.com/yuhan0/26702914130243382aeb133cfd778fc0
Feels like somewhat of a hack since the merge order isn't guaranteed, even though it seems to follow the order of aliases specified at the cli (something something ArrayMap vs HashMap)