This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-04-14
Channels
- # ai (24)
- # announcements (36)
- # babashka (15)
- # babashka-sci-dev (8)
- # beginners (18)
- # biff (4)
- # calva (24)
- # cider (13)
- # clj-kondo (1)
- # clj-on-windows (2)
- # clojars (15)
- # clojure (120)
- # clojure-dev (13)
- # clojure-europe (69)
- # clojure-nl (1)
- # clojure-norway (8)
- # clojure-uk (2)
- # clojurescript (4)
- # core-logic (2)
- # cursive (6)
- # datomic (193)
- # dev-tooling (4)
- # emacs (1)
- # hyperfiddle (57)
- # lsp (56)
- # malli (11)
- # missionary (15)
- # nbb (61)
- # off-topic (8)
- # polylith (8)
- # practicalli (2)
- # proletarian (1)
- # reitit (3)
- # releases (2)
- # remote-jobs (1)
- # shadow-cljs (13)
- # spacemacs (1)
- # specter (2)
- # sql (17)
- # tools-deps (3)
- # vim (38)
Is there a way to configure logback/log4j at runtime? (exciting logging question inside)
we're using ~this approach, using a logback.xml
in resources, and also setting up the additional config in a integrant/init-key fn
but now we want to configure the papertrail port etc. inside that integrant function, depending on the integrant configuration (because different app configs might be loaded at boot)
ideally, we pass the port to integrant and configure it there. alternatively we could have multiple logback.xml/log4j.properties and load the correct one depending on config. what is the best way to achieve that?
It's possible, I use this for Sentry:
;; Potentially useful things to consider:
;; -
;; -
;; -
;; The last two have an example usage at .
(defmethod ig/init-key ::logback
[_ {:keys [sentry]}]
(when-let [dsn (not-empty (:backend-dsn sentry))]
;; Sentry must be configured before its appender,
;; otherwise this call to `init!` will override the appender settings.
(sentry/init! dsn (dissoc sentry :backend-dsn))
(let [^LoggerContext context (LoggerFactory/getILoggerFactory)
^Logger root-logger (LoggerFactory/getLogger Logger/ROOT_LOGGER_NAME)
appender (doto (SentryAppender.)
(.setMinimumEventLevel Level/WARN)
(.setMinimumBreadcrumbLevel Level/DEBUG)
(.setContext context))]
(.addAppender root-logger appender)
(.start appender)
appender)))
Here is an example for logback: https://github.com/igrishaev/teleward/blob/master/src/teleward/logging.clj
Hello,
Does any of you encounter a strange bug using Docker Clojure image, CLI deps and tools.build when trying to use a package mirror?
The idea is to use a mirror for dependencies by defining -Sdeps
with a custom :mvn/local-repo
and hidden default "central" & "clojars" (something like: {:mvn/local-repo ".m2/repository" :mvn/repos {"central" nil "clojars" nil}}
)
Every other commands work fine, but when a execute tools.build functions my command line configuration seems ignored and packaged are downloaded again in the home user maven repository
Any idea? How can I make sure in my build.clj
that my code uses a project local maven repo?
can you clarify what you mean by "mirror"? Mirrors are a thing that Maven explicitly supports in ~/.m2/settings.xml and CLI/deps do use those if configured. but it almost sounds like you do not mean that
do you have it configured as a mirror in settings.xml?
if so, you should not have to do anything else
https://jfrog.com/help/r/jfrog-artifactory-documentation/maven-repository
I see in the Artifactory UI that it mirror various repos: clojars, central, ...
but other command like clj -M:test
do get their dependencies from the mirror and use the project local .m2 directory
the local .m2 directory is a cache, and is somewhat orthogonal
I'm not sure if it would help, but in lein, you specify the :local-repo
path, and all the packages get downloaded into it. For example, in our lein project we have a :docker
profile with settings:
:docker
{:local-repo ".docker/m2"}
When you run the docker image, you specify the profile and all the packages are downloaded once.the local repo is independent I think of the question being asked here, which is about where to get things from in the first place
@U1WAUKQ3E know that 😉 But this project uses CLI deps and to have a similar feature I use a custom deps string as arg of clojure cli
the command line args you pass to clj will not affect what happens in your build, which creates its own basis
you can pass :extra arg to create-basis to do the equivalent
but I still question whether you need to do any of that if you've configured maven properly to use artifactory
@alexmiller because everything run in a docker image in Gitlab-CI with cache configured for project local m2. Each run I can see my cache populated and every command using it, only clojure -T:build
dont wants to use it 😁
well, see my answer on that above
I can clear the cash and see on the first clojure -M
the download of packages from the mirror and my cache populated but clojure -Tbuild
just do it again ignoring my -Sdeps
config
As far as I got the question, the main problem is that CI downloads the libraries again and again. I believe, setting a local-repo would solve it. I've had the same issue on CI, the only difference is I have lein.
as I said, "the command line args you pass to clj will not affect what happens in your build, which creates its own basis. you can pass :extra arg to create-basis to do the equivalent"
@U1WAUKQ3E project using lein works fine for me too. My issues with my other project using CLI deps and tools.build 😉
ok @alexmiller , think I ll try the extra-arg solution to see where it gets me 😁
clojure -Tbuild
is running your build program. inside the build program, it determines the basis for your project - that job is completely separate from the args you passed when running the build program itself.
Just to let you know, I did removed my -Sdeps
and call my tools.build functions with a deps map to create a basis with :extra deps. It did work, but I could still see downloads from central. After few tests, I saw that I needed to keep my -Sdeps
custom map because there is the initial download of jars for tools.build itself.
But now at last, what a joy to see my initial run to download only from my mirror and my second run with a populated jars cache to get to work immediately without downloading a single jar! 🙌
Thank you Alex
@alexmiller
Follow up question (maybe bug report?) related to the just announced add-lib
functionality to Clojure:
I tested on Linux in a CLI repl started with clj
in an empty directory and everything worked great. Then I tried it by starting a CLI repl in a work repo and got this error:
Execution error (IOException) at java.lang.ProcessImpl/forkAndExec (ProcessImpl.java:-2).
error=7, Argument list too long
I started bisecting my deps.edn
file to see if I could find the problem and I found a minimal subset of the deps.edn
file which still causes the same error (I'll paste in a thread).
The surprising part is that it almost appears like the error occurs when you reach a certain size of transitive dependencies (`clj -Stree` says 222
in my minimal repro) but also appears to go away under a certain size"Minimal" deps.edn for me:
{:deps
{org.clojure/clojure #:mvn{:version "1.12.0-alpha2"},
com.google.cloud.opentelemetry/exporter-trace #:mvn{:version "0.23.0"},
ring/ring-devel #:mvn{:version "1.9.6"},
com.google.cloud/google-cloud-bigquery #:mvn{:version "2.14.6"},
com.taoensso/carmine #:mvn{:version "3.2.0"},
}}
Shell history:
clojure -version
Clojure CLI version 1.11.1.1273
√ $ clj
Clojure 1.12.0-alpha2
user=> (add-lib 'metosin/malli)
Execution error (IOException) at java.lang.ProcessImpl/forkAndExec (ProcessImpl.java:-2).
error=7, Argument list too long
user=>
commenting out any of the bottom four deps in the list and then re-running works without error
a subset of the basis gets passed to the forked command
can you just put the general problem on https://ask.clojure.org ?
there are also impacts if you have a large set of aliases in ~/.clojure/deps.edn. curious if that's true for you?
there's a couple ways to address this, I wasn't sure how common of a problem it would be
well that doesn't seem like too many, probably more the deps then.
when adding a lib, you have to resolve against the current lib set, which means you need to pass the current lib set out to tools.deps, so that's where that's coming in. I'll try to get a fix for this into alpha3
https://ask.clojure.org/index.php/12852/execution-error-java-processimpl-forkandexec-argument-using
I bet I'll run into that. I'm off today but will test it at work on Monday.
FWIW, I might be hitting a related issue. I don’t have an easy way to repro yet, but I’m using a couple of aliases that, when combined, amount to a pretty big chunk of deps, and I get Unreadable arg: "{:existing {<snip big dep map>}}"
when calling e.g. (clojure.repl.deps/add-lib 'com.github.seancorfield/next.jdbc)
. Not sure if that’s useful — I can try to come up with a repro if necessary.
Re 1.12.0-alpha2's add-lib..., it sounds like a CVE factory. To date, Clojure has a top-notch safety rating on Sonatype's Maven search. But there is no imaginable way that Maven-related version-resolution, repository-consulting, credential-handling, jar-fetching can be done in a perfectly airtight, foolproof way. It is "Incidental Complexity City"! Clojure's good reputation might suffer if protocol/network/Maven surprises got registered as a fault of Clojure instead of tools.deps. Can there be a very clear, very apparent arm's-length distance between Clojure (10-out-of-10) and the horror show of dependency resolution and such?
Such as, perhaps, configure your tools.deps-or-whatever command as a Java Property for the core Clojure. There would then be a fig leaf that "it's not really Clojure" (and also it could actually be Leiningen)
and it shells out for dependency resolution and fetching (all done in another process)
Clojure has always let you load and execute arbitrary code, and has had built-in support via clojure.java.shell for shelling out to run arbitrary things. we really haven't added much that's new to that very open set of doors. I think it's well scoped due to the process separation.
but open to thinking about whether to have knobs to turn on or off capabilities
@U0HG4EHMH You've been able to do this programmatically via clojure.tools.deps.alpha
for ages (years, at this point maybe) -- in addition to just generally loading and executing arbitrary code from anywhere at runtime (via core Clojure functionality) for even longer.
If anything, this makes it easier to go through the proper channels for code -- Clojars & Maven -- than to workaround it with the less secure options we had previously...
That requires a library to do that though right? I think the worry is that that surface is now inseparable from the language itself
read
, eval
, slurp
, load-file
, etc are core Clojure functions...
I ask only whether the bundling or advertisement of a high-risk feature as part of core Clojure puts its reputation at risk. The REPL limit and the separate-process hedge are good but they will not quell a firestorm of fud if someone finds a hole in behavior that you get out-of-the-box by installing Clojure. The CVE will cite Clojure. Might there be a more "open", less-coupled, way to accomplish add-lib that distances core Clojure from the dependency-resolution and acquisition-of-jars tar pits? An opt-in which, even if you opt in, won't be core Clojure's problem if it turns into the next Log4j disaster?
I’m not advocating either way but I do see the point that a CVE in all of that apparatus means there is a CVE in Clojure. It’s true eval
and it’s ilk let’s you do zany things, but CVEs generally mean bad things can happen when you didn’t intend to. I think it’s a good point and I’m glad @U0HG4EHMH brought it up.
Having looked at the implementation, I'm much less worried about this new feature than the existing stuff already in the language:
• add-lib etc rely on the basis
• the basis only exists in processes run via the Clojure CLI -- not via java
• the way the dependencies are analyzed/fetched is via shelling out to the clojure
command, using the :deps
alias
So if you build uberjars and run them via java
then none of this new stuff will be available inside your running program.
If you don't have the clojure
CLI installed on a target system, you can't use these new clojure.repl.deps
functions
> If you don't have the clojure CLI installed on a target system, you can't use these new clojure.repl.deps functions > Except CLI Tools is bundled with Clojure. Is it even possible to run Clojure without having CLI Tools installed? (Genuinely don't know the answer because I've never thought to try, but only raising the question rhetorically either way.) If I understand correctly?, phill's concern is not about actual risk being assumed. Rather the concern is that if CLI Tools inherits some major exploit through Maven, Clojure-the-language would also be labeled as exploitable because of the bundling.
I'd expect most people do not have the Clojure CLI installed in production: they build (uber) JARs and deploy those and run them via just java
.
The Clojure CLI is one way to run Clojure, but not the only way.
Not trying to argue. Just raising the following pseudo-philosophical question in regards to wondering how it affects the concern of Clojure possibly getting labeled with CVEs from CLI Tools: > they build (uber) JARs and deploy those and run them via just java. > Is that even "running Clojure" anymore? In some sense, you're just running Java at that point.
Well, that's how most production systems run I think...
According to the 2022 survey results: 52% use java
and a JAR. 25% use lein run
(surprised it's that high). ~24% use clojure
. So that's higher than I expected...
Maybe concern about this potential vector will drive more folks to use the java
startup approach?
But let's consider the "CVE in a Maven artifact" scenario: if your code is using that artifact, it's vulnerable no matter how it starts up -- because you have to load it somehow in order to use it.
So when do you load it? Either at build time and bundle it into your app, or (currently) at startup time via clojure
which fetches it and loads it before your code runs.
This new machinery potentially allows you to load it after startup. Either way (well, in all three ways), you're still loading and running that CVE.
For folks who worry about network connectivity etc, they're going to want as few network ops as possible to get their code running -- which is why most folks prefer the build-time bundling (in addition to those three ways to run Clojure in production, there a bunch of other options that did not involve using clojure
-- it was multiple choice).
So the "real concern" here I think, that @U0HG4EHMH is expressing is that your code might load unknown/unexpected CVEs at runtime through this machinery? So your code would need to be loading "arbitrary" dependencies at runtime -- either through code you've deliberately written to load new dependencies based on... what? User input? ...or through arbitrary code injected into your app somehow (again, where would it come from?). In the latter case -- arbitrary code injection -- Clojure already provides direct filesystem I/O (and HTTP access), the ability to run shell processes, and full code eval
uation and that's likely to be a pretty easy way for hackers to achieve their objective, without needing to rely on fetching and loading some arbitrary library from Maven or Clojars.
> So the "real concern" here I think, that @U0HG4EHMH is expressing is that your code might load unknown/unexpected CVEs at runtime through this machinery? > I hope @U0HG4EHMH will return to clarify the issue under discussion, because I read a completely different concern than that. My interpretation is that @U0HG4EHMH worries that if Clojure CLI Tools inherits a bunch of CVEs from its interactions with Maven, then Clojure itself be inadvertently listed as vulnerable on public CVE lists because CLI Tools happens to be bundled with it.
except ... it's not bundled with it
"Clojure CLI Tools inherits a bunch of CVEs from its interactions with Maven" -- that's like saying Gradle is inherently unsafe because it interacts with Maven... which doesn't make any sense to me...
Clojure (the language) is a jar that you put on the classpath of a program run in the Java runtime. The Clojure CLI is a separate tool you can optionally install on a machine that provides a CLI for downloading/managing dependencies, creating classpaths, and running Clojure programs
Ahh. Good point. If I understood the OP correctly, then I think that should solve the concern outright without doing anything.
Clojure itself does not depend on the CLI, or Maven, or dynamic library loading either as a published dependency or as a runtime dependency
This is a piece of functionality I will not be telling our security engineering team about. They'd have a conniption and need a lot of explanation, and proof that our production runtime (`java -jar uberjar.jar`) isn't able to load dependencies dynamically (it doesn't matter what you can currently technically achieve).
That conversation would be much easier if the docstring for add-lib(s)
explains the circumstances in which it's available, and those in which it isn't.
I urge an overt opt-in step, like "clojure --with-add-lib-from-tools", or better still, limit add-lib to jars you already have on your disk, because the recipe for reputational damage is pretty short: Step 1: "Install Clojure" (https://clojure.org/guides/install_clojure). Step 2: Something happens that someone thinks is unexpected or bad, which is not absurdly unlikely in the realm of finding and fetching jars from Maven repos on the internet. Step 3: The CVE says "Clojure" because that's what you installed. FUD riots trample the nuances. P.S. Can you rebind repl?
The first two steps already existed in the Clojure CLI and every user of Maven, Gradle, sbt etc. This is just FUD.
I'm stepping out of this thread. @U0HG4EHMH You are not addressing any of the specifics that you've been asked about how you imagine a real-world exploit to actually happen here, with this new feature, that can't already happen with a Clojure program.
i assumed that the feature brought in more jars like maven libraries to the clojure.jar and thought it was a good point at first. Seeing that that is not the case I’m not worried and quite excited to try the new functionality. I think i gave the FUD more life than it should have an i apologize for that.
SOLVED
Hello -- I’d like to write a macro to automate spec-defining
for enum-like sets. Although my MVE here looks useless, in
context of my real application (a compiler’s IR), such
automation saves a lot of repetition. I stripped out the
context to make an MVE for this question.
Here is an example of the result I want. This works fine and
defines the spec ::storage-type-enum
, which is the same as
:msmve.core/storage-type-enum
:
(ns msmve.core
(:require [clojure.spec.alpha :as s]
[hyperfiddle.rcf :refer [tests tap %]])
(:gen-class))
(hyperfiddle.rcf/enable!) ;; lightweight, load-time testing
;; HERE IS THE SPEC:
(s/def ::storage-type-enum #{'Default, 'Save, 'Parameter, 'Allocatable})
(tests
(s/valid? ::storage-type-enum 'Default) := true
(s/valid? ::storage-type-enum 'foobar) := false)
Here is my attempt at a macro:
(defmacro enum-like [term, heads]
`(let [tke# (keyword "msmve.core" (str '~term "-enum"))]
(s/def tke# ~heads))) ;; SHOULD REGISTER THE SPEC!!!
(enum-like storage-type #{'Default, 'Save, 'Parameter, 'Allocatable})
But the spec isn’t registered, even though the keyword tke#
seems
correctly constructed:
(keyword "msmve.core" (str 'storage-type "-enum"))
:msmve.core/storage-type-enum
Here is an abbreviated trace:
ERROR in () (:)
expected: (hyperfiddle.rcf/= (s/valid? :msmve.core/storage-type-enum (quote foobar)) false)
actual: java.lang.Exception: Unable to resolve spec: :msmve.core/storage-type-enum
at clojure.spec.alpha$reg_resolve_BANG_.invokeStatic (alpha.clj:76)
clojure.spec.alpha$reg_resolve_BANG_.invoke (alpha.clj:71)
clojure.spec.alpha$fn__1797.invokeStatic (alpha.clj:139)
clojure.spec.alpha/fn (alpha.clj:137)
clojure.spec.alpha$fn__1776$G__1771__1785.invoke (alpha.clj:128)
clojure.spec.alpha$specize.invokeStatic (alpha.clj:159)
clojure.spec.alpha$specize.invoke (alpha.clj:158)
clojure.spec.alpha$valid_QMARK_.invokeStatic (alpha.clj:775)
clojure.spec.alpha$valid_QMARK_.invoke (alpha.clj:772)
msmve.core$eval8441.invokeStatic (core.clj:14)
msmve.core$eval8441.invoke (core.clj:14)
...
I’d be grateful for advice!s/def
is a macro by itself - you can't pass it a symbol and have it resolved that way.
You have to compose a keyword in your macro itself, and then insert it into the (s/def ...)
form so it actually becomes (s/def :msmve.core/... ...)
instead of (s/def tke__1 ...)
.
Just in case - if you ever feel like you need to create specs in run time or simply have to apply a lot of logic during spec creation, it might be better to use some other spec'ing library, e.g. Malli.
BTW, it's better to create shorter questions and provide more details in a thread. This way, a question doesn't span a few pages on everyone's screen and lets people see whether they can answer it immediately.
Oh, and just a tiny thing - inserting manual line breaks to keep lines short is not necessary. :) It might be your editor doing that, of course, but in general it's not necessary here at all because everyone can adjust the width of the chat area in Slack to their preference.
So to help out a bit more, you can do this by lifting the creation of the keyword to outside of your syntax quote.
(let [tke (keyword "msmve.core" (str term "-enum"))]
`(s/def ~tke ~heads))
@U2FRKM4TW thanks for the meta-advice, too 🙂 I find these web-app embedded editors maddening because my fingers automatically type Emacs keybindings and they wreak havoc, so I pre-edit and then paste. I’ll not shorten lines and I will shorten questions in the future!
> inserting manual line breaks to keep lines short ... in general it's not necessary here at all because everyone can adjust the width of the chat area in Slack to their preference. > Very short line lengths, when it's reasonable to do so, can be extremely helpful for people on cell phones, where line wrapping can often make large code blocks almost unreadable. (I am reading right now on a Fold 3, and even when opened to the larger tablet-like screen, I still see too much wrapping in the code above.)
> wrapping can often make large code blocks almost unreadable I wasn't talking about code. And I'd argue that inserting extra line breaks to make some code more readable for mobile users will also make it less readable for desktop/laptop users. Otherwise such code should've been formatted that way from the get go.
> I wasn't talking about code. > Oh, then yeah. 💯 agreed. > inserting extra line breaks to make some code more readable for mobile users will also make it less readable for desktop/laptop users. > Definitely depends on the circumstance. That falls under my "when it's reasonable to do so" qualification, where the two main factors to "reasonable" are 1. how much code would need to be edited just for Slack and 2. how ridiculous would it make that particular code sample look with everything slammed over to the left using extra lines.
Clojure 1.12 Alpha 2: loading the test dependencies of a library you're using, into your REPL
(require '[clojure.repl.deps :refer [add-libs]]
'[clojure.edn :as edn])
(def test-deps (-> (slurp "")
(edn/read-string)
:aliases
:test
:extra-deps))
(add-libs test-deps)
(this is from the test-fixtures
ns in next.jdbc
and I was previously doing this via the experimental add-libs branch of t.d.a)
hello, how can I run this command in clojure.java.shell/sh
:
clojure -M:my-fn < data.json
I am trying this but it’s not working:
(sh "clojure" "-M:my-fn" "<" "data.json")
Runs fine in the terminal.
It is for an integration test.not sure if this is the correct method (but feels pretty solid) but the docstring tells you how to achieve this:
clojure.java.shell/sh
([& args])
Passes the given strings to Runtime.exec() to launch a sub-process.
Options are
:in may be given followed by any legal input source for
, e.g. InputStream, Reader, File, byte[],
or String, to be fed to the sub-process's stdin.
Like this? (sh "clojure" "-M:my-fn" :in "data.json")
. Not working for me.
What’s a good way to test that then?
You can write the contents of data.json to the stdin of the process, which is what is being suggested up above
When you pass a string the string itself is passed as input, not the file named by the string
user=> (with-open [in ( "input.txt")]
(clojure.java.shell/sh "cat" :in in))
{:exit 0, :out "hello from clojure java shell\n", :err ""}
user=> (clojure.java.shell/sh "cat"
:in ( "input.txt"))
{:exit 0, :out "hello from clojure java shell\n", :err ""}
you can even pass it a file and it handles it for you. (as it says, anything that io/copy
knows how to work withI generally prefer using ProcessBuilder directly, you can get an output steam that connects to the processes stdin and write whatever you want to
And in Clojure 1.12.0 Alpha 2, there's clojure.java.process
which wraps ProcessBuilder
🙂
This is what I have in my -main
fn, but I can’t get any of the suggestions to work
(defn -main [& input-data]
(println (or input-data (-> *in* slurp (str/split #"\n")))))
Output is different when called from the shell vs the options above
Different how?
(~/clojure)-(!2011)-> clojure -M:my-fn < deps.edn
[{:deps {org.clojure/clojure {:mvn/version "1.12.0-alpha2"}} :aliases { :my-fn {:main-opts ["-m" "diego"]} :hiccup {:extra-deps {hiccup/hiccup {:mvn/version "RELEASE"}}} :build {:deps {io.github.clojure/tools.build
{:git/tag "v0.9.4" :git/sha "76b78fe"}} :ns-default build} }}]
Fri Apr 14 17:16:31
(~/clojure)-(!2012)-> clj
Clojure 1.12.0-alpha2
user=> (require '[clojure.java.process :as p])
nil
user=> (p/exec {:in (p/from-file "deps.edn")} "clojure" "-M:my-fn")
"[{:deps {org.clojure/clojure {:mvn/version \"1.12.0-alpha2\"}} :aliases { :my-fn {:main-opts [\"-m\" \"diego\"]} :hiccup {:extra-deps {hiccup/hiccup {:mvn/version \"RELEASE\"}}} :build {:deps {io.github.clojure/tools.build
{:git/tag \"v0.9.4\" :git/sha \"76b78fe\"}} :ns-default build} }}]"
user=>
That's with
(~/clojure)-(!2013)-> cat src/diego.clj
(ns diego
(:require [clojure.string :as str]))
(defn -main [& input-data]
(println (or input-data (-> *in* slurp (str/split #"\n")))))
yes, cat
works fine but I am using <
(as in clojure -M:my-fn < data.json
) and the behavior is different depending on the suggestion.
ended up with this (sh "bash" "-c" "clojure -M:my-fn < data.json")
Huh? I only used cat
to show what's in src/diego.clj
What I'm saying is that clojure -M:my-fn < deps.edn
and (p/exec {:in (p/from-file "deps.edn")} "clojure" "-M:my-fn")
are equivalent -- but I'm not sure what you're saying is different?
Oh I see @U04V70XH6, missed one of your messages. Thanks, I’ll keep that in mind for the future. Though I think I will stay with the bash
call as it better represents the use case that I am trying to test.
@U7AMPCPU2 Well, @U11BV7MTK’s suggestion seems to work too (with Clojure 1.11):
(~/clojure)-(!2006)-> clj -M:1.11
Clojure 1.11.1
user=> (require '[clojure.java.shell :as sh] '[ :as io])
nil
user=> (:out (sh/sh "clojure" "-M:my-fn" :in (io/file "deps.edn")))
"[{:deps {org.clojure/clojure {:mvn/version \"1.12.0-alpha2\"}} :aliases { :my-fn {:main-opts [\"-m\" \"diego\"]} :hiccup {:extra-deps {hiccup/hiccup {:mvn/version \"RELEASE\"}}} :build {:deps {io.github.clojure/tools.build
{:git/tag \"v0.9.4\" :git/sha \"76b78fe\"}} :ns-default build} }}]\n"
user=>
You are right, it does, must have made a mistake.