Fork me on GitHub
#clojure
<
2023-04-14
>
michihuber10:04:09

Is there a way to configure logback/log4j at runtime? (exciting logging question inside)

michihuber10:04:33

we're using ~this approach, using a logback.xml in resources, and also setting up the additional config in a integrant/init-key fn

michihuber10:04:19

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)

michihuber10:04:27

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?

p-himik10:04:04

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)))

👍 2
rolt11:04:47

+1 for unilog if you're not dead set on using logback.xml files

kawas14:04:08

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?

Alex Miller (Clojure team)14:04:00

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

kawas14:04:57

My mirror is an intern Artifactory server

Alex Miller (Clojure team)14:04:19

do you have it configured as a mirror in settings.xml?

Alex Miller (Clojure team)14:04:26

if so, you should not have to do anything else

kawas14:04:35

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

Alex Miller (Clojure team)14:04:28

the local .m2 directory is a cache, and is somewhat orthogonal

igrishaev14:04:57

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.

Alex Miller (Clojure team)14:04:02

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

kawas14:04:13

@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

Alex Miller (Clojure team)14:04:55

the command line args you pass to clj will not affect what happens in your build, which creates its own basis

Alex Miller (Clojure team)14:04:16

you can pass :extra arg to create-basis to do the equivalent

Alex Miller (Clojure team)14:04:39

but I still question whether you need to do any of that if you've configured maven properly to use artifactory

kawas14:04:55

@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 😁

Alex Miller (Clojure team)14:04:01

well, see my answer on that above

kawas14:04:18

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

igrishaev14:04:28

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.

Alex Miller (Clojure team)14:04:05

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"

kawas14:04:15

@U1WAUKQ3E project using lein works fine for me too. My issues with my other project using CLI deps and tools.build 😉

kawas14:04:54

ok @alexmiller , think I ll try the extra-arg solution to see where it gets me 😁

Alex Miller (Clojure team)14:04:25

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.

👌 4
kawas16:04:54

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

adamfrey15:04:05

@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

adamfrey15:04:55

"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"},
  }}

adamfrey15:04:23

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=> 

adamfrey15:04:50

commenting out any of the bottom four deps in the list and then re-running works without error

Alex Miller (Clojure team)15:04:47

a subset of the basis gets passed to the forked command

Alex Miller (Clojure team)15:04:57

can you just put the general problem on https://ask.clojure.org ?

Alex Miller (Clojure team)15:04:27

there are also impacts if you have a large set of aliases in ~/.clojure/deps.edn. curious if that's true for you?

adamfrey15:04:28

yep. Thanks

adamfrey15:04:40

ahh, good point I didn't think about that

Alex Miller (Clojure team)15:04:00

there's a couple ways to address this, I wasn't sure how common of a problem it would be

adamfrey15:04:29

I have a 9 aliases in ~/.clojure/deps.edn

Alex Miller (Clojure team)15:04:01

well that doesn't seem like too many, probably more the deps then.

Alex Miller (Clojure team)15:04:24

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

seancorfield18:04:29

I bet I'll run into that. I'm off today but will test it at work on Monday.

flowthing19:04:25

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.

phill16:04:09

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?

phill16:04:10

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)

hiredman16:04:22

have you looked at the add-lib stuff?

hiredman16:04:52

there is explicitly an var bound to try and limit its use to within the repl

hiredman16:04:27

and it shells out for dependency resolution and fetching (all done in another process)

Alex Miller (Clojure team)17:04:15

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.

Alex Miller (Clojure team)17:04:34

but open to thinking about whether to have knobs to turn on or off capabilities

seancorfield18:04:39

@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...

dpsutton19:04:53

That requires a library to do that though right? I think the worry is that that surface is now inseparable from the language itself

seancorfield19:04:02

read, eval, slurp, load-file, etc are core Clojure functions...

phill23:04:02

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?

dpsutton23:04:25

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.

seancorfield23:04:29

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

skylize13:04:23

> 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.

seancorfield15:04:08

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.

seancorfield15:04:48

The Clojure CLI is one way to run Clojure, but not the only way.

skylize15:04:11

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.

seancorfield15:04:50

Well, that's how most production systems run I think...

seancorfield15:04:52

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...

seancorfield15:04:38

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).

seancorfield16:04:33

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 evaluation 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.

skylize17:04:22

> 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.

Alex Miller (Clojure team)17:04:15

except ... it's not bundled with it

seancorfield17:04:16

"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...

Alex Miller (Clojure team)17:04:47

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

skylize17:04:03

Ahh. Good point. If I understood the OP correctly, then I think that should solve the concern outright without doing anything.

Alex Miller (Clojure team)17:04:10

Clojure itself does not depend on the CLI, or Maven, or dynamic library loading either as a published dependency or as a runtime dependency

gordon11:04:10

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.

phill16:04:46

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?

Alex Miller (Clojure team)17:04:20

The first two steps already existed in the Clojure CLI and every user of Maven, Gradle, sbt etc. This is just FUD.

seancorfield17:04:56

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.

dpsutton18:04:34

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.

Brian Beckman18:04:06

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!

🏁 2
p-himik18:04:01

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.

👍 6
p-himik18:04:32

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.

👍 2
p-himik18:04:20

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.

👍 2
Joshua Suskalo18:04:59

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))

🏁 2
Brian Beckman19:04:23

@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!

skylize13:04:24

> 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.)

p-himik14:04:17

> 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.

skylize14:04:31

> 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.

seancorfield23:04:46

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)

nice 6
😮 4
metal 2
seancorfield23:04:46

(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)

diego.videco23:04:43

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.

dpsutton23:04:43

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.

diego.videco23:04:47

Like this? (sh "clojure" "-M:my-fn" :in "data.json"). Not working for me.

hiredman23:04:58

clojure.java.shell is misnamed

hiredman23:04:06

No shell involved at all

hiredman23:04:26

And pipes and redirects like that are shell features

diego.videco23:04:59

What’s a good way to test that then?

hiredman23:04:10

You can write the contents of data.json to the stdin of the process, which is what is being suggested up above

hiredman23:04:29

You need to make an inputsream and pass it in as :in

hiredman23:04:08

When you pass a string the string itself is passed as input, not the file named by the string

dpsutton23:04:21

user=> (with-open [in ( "input.txt")]
         (clojure.java.shell/sh "cat" :in in))
{:exit 0, :out "hello from clojure java shell\n", :err ""}

dpsutton23:04:43

(the with-open is not needed. i was checking with something else at first)

dpsutton23:04:59

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 with

hiredman23:04:05

I generally prefer using ProcessBuilder directly, you can get an output steam that connects to the processes stdin and write whatever you want to

seancorfield00:04:31

And in Clojure 1.12.0 Alpha 2, there's clojure.java.process which wraps ProcessBuilder 🙂

👀 2
diego.videco00:04:56

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")))))

diego.videco00:04:15

Output is different when called from the shell vs the options above

seancorfield00:04:20

Different how?

seancorfield00:04:31

(~/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=>

seancorfield00:04:53

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")))))

diego.videco00:04:27

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.

diego.videco00:04:58

ended up with this (sh "bash" "-c" "clojure -M:my-fn < data.json")

seancorfield00:04:00

Huh? I only used cat to show what's in src/diego.clj

seancorfield00:04:11

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?

diego.videco00:04:15

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.

seancorfield00:04:36

@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=>

diego.videco00:04:19

You are right, it does, must have made a mistake.