This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-05-01
Channels
- # announcements (6)
- # babashka (8)
- # beginners (16)
- # calva (36)
- # clara (3)
- # clerk (6)
- # clj-commons (9)
- # clj-kondo (59)
- # clojure (174)
- # clojure-europe (13)
- # clojure-nl (1)
- # clojure-norway (3)
- # clojure-uk (7)
- # conjure (1)
- # cursive (44)
- # datomic (8)
- # events (1)
- # gratitude (1)
- # hyperfiddle (7)
- # introduce-yourself (1)
- # keechma (1)
- # london-clojurians (1)
- # missionary (2)
- # off-topic (20)
- # ring-swagger (1)
- # squint (37)
If I’ve rebound a dynamic var using binding
, is there any way to get the original value while inside the rebound section? In my case, I’ve rebound clojure.test/report
but I’d like to access the original version to delegate to that. Obviously I could capture it before binding and then pass the original to the bound version in a closure or something, but I thought I’d check that I wasn’t missing another easier solution.
But that may or may not be the same as the value before you bound it, so better to capture what you see before binding and delegate
Right, I guess there could theoretically be multiple binding scopes. I’ll capture beforehand, thanks.
Eh, I feel I have open-source paralysis. I've been sitting on two libs that I thought I'd open-source, but I keep feeling like they're not "done enough", and like I might want to still change some things, etc. Any tips?
Publish them as "0.0.1" or similar and say they're "subject to change based on feedback from users" in the README.
You won't get feedback without publishing them!
I have too high expectations for my online publications lol, way more than at my work haha
Just do it! There’s basically no downside. The worst outcome is people will ignore it. You can always announce again after an update.
"read the source" -- isn't that the Clojure Way(tm)?
The library doesn't need to be completed or perfect code. I do suggest deciding on a license before releasing, especially if there is an expectation of contributions from other developers. You should also ensure you have the right to open source all the code (no restrictive license or ownership issues). I would also include a Readme with a meaningful summary of the library and at least a few basic examples, assuming there is a desire for people to become interested in the library.
The readme doesn't have to be polished but at least inform people about the library, it's current state and maybe your plans. Then they can decide, if it's worth their time looking into it and give feedback.
Other question, I see this in the clojure cli help: > Programs provided by :deps alias: > -X:deps list List full transitive deps set and licenses > -X:deps tree Print deps tree > -X:deps find-versions Find available versions of a library > -X:deps prep Prepare all unprepped libs in the dep tree > -X:deps mvn-pom Generate (or update) pom.xml with deps and paths > -X:deps mvn-install Install a maven jar to the local repository cache > -X:deps git-resolve-tags Resolve git coord tags to shas and update deps.edn Is there a new feature that alias can like add to the help? Or is this just hard-coded for this one alias?
It's hard coded. clojure --help
doesn't run any code -- just the clojure
shell script.
(the help text is printed directly by the shell script)
clojure -M:some-alias --help
🙂
(that passes ["--help"]
to the :main-opts
behind :some-alias
)
There have been several requests for an option to list all the :aliases
available (across root + user + project) -- I'm not sure any of those requests made it into an Ask or a Jira ticket tho'...
As for invocation, any alias can be invoked via -M
, -X
, or -T
-- the behavior depends on what that alias provides and what other aliases you request so no single alias can tell you that.
It's common for libraries & tools to offer an alias which can be invoked via multiple of those options. See Cognitect's test-runner
which provides a single alias for both -M
and -X
usage: https://github.com/cognitect-labs/test-runner?tab=readme-ov-file#configuration
The tool/lib would know what different invokation ways it supports no? So why couldn't it tell me/the cli ?
is a thing
Somehow I had missed (or forgotten) about aliases
. However:
(/var/www/worldsingles)-(!2005)-> clojure -X:deps aliases
Execution error (ClassCastException) at clojure.tools.deps.cli.api/aliases$fn$fn (api.clj:170).
class java.lang.String cannot be cast to class java.util.Map$Entry (java.lang.String and java.util.Map$Entry are in module java.base of loader 'bootstrap')
Full report at:
/tmp/clojure-18433377707917027348.edn
{:clojure.main/message
"Execution error (ClassCastException) at clojure.tools.deps.cli.api/aliases$fn$fn (api.clj:170).\nclass java.lang.String cannot be cast to class java.util.Map$Entry (java.lang.String and java.util.Map$Entry are in module java.base of loader 'bootstrap')\n",
:clojure.main/triage
{:clojure.error/class java.lang.ClassCastException,
:clojure.error/line 170,
:clojure.error/cause
"class java.lang.String cannot be cast to class java.util.Map$Entry (java.lang.String and java.util.Map$Entry are in module java.base of loader 'bootstrap')",
:clojure.error/symbol clojure.tools.deps.cli.api/aliases$fn$fn,
:clojure.error/source "api.clj",
:clojure.error/phase :execution},
:clojure.main/trace
{:via
[{:type java.lang.ClassCastException,
:message
"class java.lang.String cannot be cast to class java.util.Map$Entry (java.lang.String and java.util.Map$Entry are in module java.base of loader 'bootstrap')",
:at
[clojure.lang.APersistentMap$KeySeq
first
"APersistentMap.java"
171]}],
:trace
[[clojure.lang.APersistentMap$KeySeq first "APersistentMap.java" 171]
[clojure.lang.RT first "RT.java" 712]
[clojure.core$first__5456 invokeStatic "core.clj" 55]
[clojure.core$reduce1 invokeStatic "core.clj" 946]
[clojure.core$set invokeStatic "core.clj" 4129]
[clojure.core$set invoke "core.clj" 4121]
[clojure.tools.deps.cli.api$aliases$fn__3554$fn__3555
invoke
"api.clj"
170]
[clojure.lang.PersistentHashMap$NodeSeq
kvreduce
"PersistentHashMap.java"
1309]
[clojure.lang.PersistentHashMap$BitmapIndexedNode
kvreduce
"PersistentHashMap.java"
804]
[clojure.lang.PersistentHashMap
kvreduce
"PersistentHashMap.java"
238]
[clojure.core$fn__8527 invokeStatic "core.clj" 6977]
[clojure.core$fn__8527 invoke "core.clj" 6957]
[clojure.core.protocols$fn__8267$G__8262__8276
invoke
"protocols.clj"
174]
[clojure.core$reduce_kv invokeStatic "core.clj" 6988]
[clojure.core$reduce_kv invoke "core.clj" 6979]
[clojure.tools.deps.cli.api$aliases$fn__3554 invoke "api.clj" 167]
Sounds like a string where a map should be somewhere?
@U064X3EF3 it's our main deps.edn
at work, so it is perfectly valid...
@U0K064KQV oh you mean https://clojure.org/reference/clojure_cli#deps_prep
@U04V70XH6 hard to say without files
Here's a repro for you:
(~/clojure/t)-(!2011)-> cat > deps.edn
{:aliases {:foo ["some" "data"]}}
Tue Apr 30 22:33:28
(~/clojure/t)-(!2012)-> clj
Clojure 1.12.0-alpha11
user=>
Tue Apr 30 22:33:37
(~/clojure/t)-(!2013)-> clojure -X:deps aliases
Execution error (ClassCastException) at clojure.tools.deps.cli.api/aliases$fn$fn (api.clj:170).
class java.lang.String cannot be cast to class java.util.Map$Entry (java.lang.String and java.util.Map$Entry are in module java.base of loader 'bootstrap')
Full report at:
/tmp/clojure-4544942395618193305.edn
Alias-as-data is perfectly valid.
If you can put it on ask I’ll get to it
https://ask.clojure.org/index.php/13867/clojure-x-deps-aliases-fails-for-alias-as-data
@U0K064KQV Do you use zsh? I have this in my .zshrc
to tab complete aliases. It relies on bb
being installed and it's not exactly complete, but it might help you remember the aliases?
function cljCompletions {
if [ -e deps.edn ] && which bb >/dev/null ; then
if echo "${LBUFFER}" | grep -E '(clojure|clj) .*-X:deps *[^- ]*$' >/dev/null 2>&1 ; then
reply=(list tree find-versions prep mvn-pom mvn-install git-resolve-tags)
elif echo "${LBUFFER}" | grep -E '(clojure|clj) .*-[XMA]:[^ ]*$' >/dev/null 2>&1 ; then
existing_aliases=$(echo "${LBUFFER}" | sed 's/.*\(-[XMA].*\):[^:]*/\1/')
prefix=$(echo "${LBUFFER}" | sed 's/.*:\([^:]*\)/\1/')
reply=($((echo '[' ; cat deps.edn ~/.clojure/deps.edn ; echo ']') | bb -o '(->> *input* (mapcat (comp keys :aliases)) (filter #(.startsWith (str %) ":'${prefix}'")) (map #(str "'${existing_aliases}'" %)) distinct sort)'))
else
reply=(-X -A -M -T -P -Sdeps -Spath -Stree -Scp -Srepro -Sforce -Sverbose -Sdescribe -Sthreads -Strace --version --init --eval --report --main --repl --help -X:deps)
fi
fi
}
compctl -K cljCompletions clj
compctl -K cljCompletions clojure
So if I type clj -X:
I get a list of aliases to complete.I have a 100k+ LOC project where if i leave the REPL running for a while, it gets into an invalid state, and M-x cider-ns-refresh stops working, with this error
No implementation of method: :into-middleware of protocol:
#'com.megacorp/IntoMiddleware found for class: com.megacorp.Middleware
The only way to recover the REPL session is to clear the tools namespace NS tracker, with double prefix arg
I understand at a high level obviously what's going on, the defrecord
expression for class 'Middleware' gets reevaluated and the corresponding extend-protocols for 'IntoMiddleware', don't get reloaded/reevaluated. I double checked all my namespace declarations :requires
to make sure the namespace dependency graph is sound.. and it looks fine to me. If there's any other tips here to pass on, please share.It probably doesn't depend on the size of the project and on the specifics of reloading and :requires
themselves.
But rather, something holds a reference to an instance of Middleware
and that instance isn't re-created when Middleware
is reloaded.
tools.namespace
can track namespaces but it can't track things you pass around when they go beyond what can be directly mapped onto the ns graph.
That issue has been there forever https://github.com/clojure/tools.namespace?tab=readme-ov-file#warnings-for-protocols
Metadata-based protocol extension is immune to it.
If you can't do that refactor immediately, you can move the defprotocol out of the t.n refresh-dirs
If you switch to clj-reload (also supported by CIDER!), adding ^:clj-reload/keep
to defprotocols should work (no personal guarantee 😄 but it would make sense to me)
https://github.com/tonsky/clj-reload?tab=readme-ov-file#usage-keeping-vars-between-reloads
@U45T93RA6 i'm using clj-refactor now very cool, i didn't quite understand how to get M-x cider-ns-refresh using it though (?)., and the link you sent doesn't document that.
ah ok, i think i see now, https://github.com/clojure-emacs/cider/pull/3624/files, i must have an outdated version of cider since i don't have cider-ns-code-reload-tool
Anyone has some experience with datascript and sql storage? Is it good any downsides. Performance issues or such. Just considering it in my app.
The question is very vague and there's a lot of room for subjectivity. Regarding performance - you can always find an SQL-compatible DB that's going to be faster in your particular scenario, with or maybe without a relevant tuning. But it might easily be the case that it's not important at all for that particular app.
If there's no good reason for any particular choice here, choose something that you know the least - it will be a good way to learn about the thing. But try to keep all the queries abstracted away to a large degree. It'will be useful if you decide to switch, but it's often useful by itself.
Yeah i thought that might be the answere i'm really curious about datomic and thought datascript might be something thats like it and production ready
Datomic used to be paid. That changed last year! Here’s the “it’s free now” announcements for pro/cloud: pro: https://blog.datomic.com/2023/04/datomic-is-free.html cloud: https://blog.datomic.com/2023/06/datomic-cloud-is-free.html
Do anyone knows a decent http stub lib?
Stub as in faking responses to requests made by a http client? The only one I'm aware of is https://codeberg.org/valpackett/clj-http-fake
@U0JEFEZH6 thanks! looks interesting this lib just replace clj-http.core/request
i dont know, maybe it will be better to use http://wiremock.org
I've used https://github.com/ring-clojure/ring-mock to create a basic Ring-compliant request skeleton
@U45T93RA6 ring-mock about testing your app api but i need to stub external service api
@U0569GLFZ looks interesting thanks!
@U5RCSJ6BB looks cool, thanks!
I just spent half an hour trying to understand why my code still worked after I forgot to call "first" before passing a value to my function.
Apparently destructuring a list as if it were a map works, it will call first
on the list itself.
(let [{:keys [foo bar]} (list {:foo 41 :bar 12})]
[foo bar])
;; => [41 12]
What's the reasoning behind the feature? I can't imagine it's to help airheads that forget to call first themselves 🙂Might have to do with https://clojure.org/news/2021/03/18/apis-serving-people-and-programs destructuring of either seqs of kvs or a map. Also works:
(let [{:keys [foo bar]} (list :foo 41 :bar 12)]
[foo bar])
It's not a feature by itself, it's a consequence of the changes in 1.11 where a function like (defn f [& {:as x}] ...)
can now be called not only as (f :a 1 :b 2)
but also as (f {:a 1 :b 2})
.
But I'd expect the destructured map to be preceded by a &
in that case, but maybe it works either way
Thanks, I see where it comes from now. I'm not a fan of the behaviour, but I imagine avoiding it would have significantly increased the complexity of the kwargs feature
Clojure is full of things that work in a particular way just because of the implementation of something else.
I'm okay with kwargs itself, but I wouldn't consider (my-func a-list-variable)
a kwargs scenario
But yeah I'd expect it to be triggered by a &
first, but I personally like the pattern of collecting up KVs into a map in an apply way
But this isn't really collecting KVs, it's having a list of maps and retrieving the first element of that list
To maybe save everyone a bit of time in case there are some misunderstandings - this very thing has been asked more than once before. E.g. this is the most recent discussion that I could find (where I also link to another discussion on the same topic): https://clojurians.slack.com/archives/C03S1KBA2/p1707982404402549
There are actually some places where we're first
ing into args when it's obviously the only thing you want, I think
Yeah, I was just trying to remember a situation in which I recall parameters would sometimes refer to the first arg as the val but when there's more than one arg it's treated as a list of vals, but maybe I'm not remembering correctly
Well, in clj, if you pass 2 args to a sugared fn with only a %
, then it'll throw about the wrong number of args. CLJS is more lenient, and I thought CLJS was giving you (1 2)
for (#(do %) 1 2)
but you're right it's 1
IDK, I reimpled sugared fns in perc for fun and I thought I recalled first'ing into the params in some situation so as to align with CLJ/S's semantics, but I'm not recalling the situation now. Yeah, my bad! You're right % is %1
Also, the meaning of %&
depends on what numbered %
s you put in your form:
(#(do [%& %1 %]) 1 2 3 4) ;=> [(2 3 4) 1 1]
(#(do [%& %2 %1 %]) 1 2 3 4) ;=> [(3 4) 2 1 1]
Which seems obvious but I never noticed it until implementing it:
(#(do [%& %3 %1 %]) 1 2 3 4) ;=> [(4) 3 1 1] <- 2 is gone
re https://clojurians.slack.com/archives/C03S1KBA2/p1714581950874359?thread_ts=1714580544.135239&cid=C03S1KBA2: I can certainly attest to that! stumbled onto this gem while I was debugging an issue some time ago:
CLJS: (* 3600 nil)
=> 0
Clojure: (* 3600 nil)
=> error!
We have a couple of git dependencies in our "production" deps. In one case we're relying on a PR to a repo that hasn't been merged (so that library is published to maven/clojars but we can't use the most recent version there due to a bug). Other than those, all of our git dependencies are for dev tooling. If a dev tool is published to clojars, we tend to use that version just so we don't need to track SHAs when the lib is updated (`antq` would tell us a newer git tag is available but not the SHA, so we'd have to go look that up ourselves). But, overall, I'm perfectly happy with git-only dependencies. I really like being able to depend on a PR while waiting for it to be merged.
(now I look, that PR did get merged -- two years ago -- but no release has been made to clojars yet containing that fix... so, still a git dep)
I'm really glad the feature exists, but relying on it a bunch makes me a little nervous, because I think GH has rate limits that are easy to trip. I know there are ways around it, but you may not discover all affected places immediately.
Hum, good point. I also think it's harder for companies who have a policy of having internal artifact repo for reliability. Like if they use artifactory, and that won't support git-deps.
In our CI pipeline, where we build artifacts for deployment, we cache .gitlibs
which is where git deps are downloaded to, so they're only re-fetched when the version changes (or the cache is cleared, which I think happens once a week by default with BitBucket Pipelines).
But, yeah, I can see how some companies might find git deps to be against policy.
I don't think there's anything wrong with git deps. It can inconvenience lein users. There's also a few other tradeoffs: • It's a little more annoying to include java classes (which may require a prep step) • Git deps might include extra files that aren't needed for release • Git deps are generally unavailable to maven consumers (eg. a java application can more easily obtain a maven jar and use it directly). However, it's really nice for trying out pre-release versions, branches, etc.
Is there any reason that lein can't support git deps or is it just something that lein hasn't implemented?
There's a fairly widely-used plugin for Leiningen that adds git dep support -- but it hasn't been updated in years.
I believe it also doesn't handle prepping (which isn't always required).
> Is there any reason that lein can't support git deps or is it just something that lein hasn't implemented?
You still would need a way to lookup transitive deps which usually means understanding deps.edn
.
Yeah, I guess there's no way a lein project could work with git deps if there isn't a deps.edn
in the project, right?
You could theoretically write a lein plugin that can parse a project.clj or deps.edn in the linked git repo.
@U04V70XH6 The current version of antq
does tell you about the latest SHA.
Also, just in case, it's somewhat new --changes-in-table
flag makes the output much nicer when you have a wide enough screen.
One reason to publish on Maven Central is reach. All large enterprises will be set up to allow access to Maven the Central and typically have a local cache service for it. This is one reason org.clojure/clojure
is publish on Maven Central.
Publish libs on Maven Central if intent is to reach a very wide audience (JVM development)
Publish on Clojars for the Clojure community
Publish on git for projects using Clojure CLI
Of course all three could be used, providing their various strengths.
Automating builds for Clojars and Maven Central is a highly effective way of keeping published libraries up to date.
The mvn based publishing also solves the issue of the double commit to update the README with the sha
For private libraries I wish we were only using git deps personally (and hope we'll move to that only). It solves the dependency confusion attacks issue nicely. There's only a single place where to find a dependency, no risk with scanning N maven repos wildly like it's the norm now. Some would argue that maven/clojars & co are "safe" as long as you follow some rules, but that makes security management more complicated to have multiple sources for downloads, credentials and so on. Another plus is that it reduces CI/CD times, and the workflow to test something from a PR in a repo to another one in a separate repo is way nicer, no risk to push potentially non functioning builds with an upstream consumer for an in-flight PR (that should never happen, but it happens in practice). Then git deps are not github only (thinking about rate limits), you can host your own repos quite easily or use some offering from people doing that for you.
lein git plugins are all kind of broken (last time I tried), the dependency resolution algos between lein and t.deps are very different, so you can end up with different outcomes. Then there's the problem of transitive deps using git coords internally as well and so on. It's probably why most of these plugins are archived/dead; it's not easy, and probably not worth the time given how nice t.deps/clj has gotten.
I see. Well work is where I see issue with git deps. Reliance on github or some external repo. No commercial artifactory for those yet, would need custom solution. Prep-lib runs arbitrary code on your build machine/local machine. It might be nicer for name squatting like you said though. But I also feel central/clojars solve that pretty well with their verified domain.
well, domains expire, and people take over these, create new verified accounts on maven (or others) and potentially poison builds you could rely on (from external libs) that do not exist yet on one of the artifact repo you might rely on, etc etc
it's a real concern. Basically unless you have the ability to express what repo should be checked per maven coord, you're potentially at risk
and you end up having to vet every single dependency vs just just use a git url, done 🙂
domain http://foo.com expires, somebody buys it, creates an account on the one where it doesn't exist. not nice
say you own http://foo.com on clojars and publish there. fine
http://foo.com expires, because reasons
Yes, you're right, a domain expiring, someone else buying it, they then can go and verify, etc. That's true.
Well, to what extent though. Is this in the same vain as a compromised git account for example?
I do personally think Clojars was a mistake. Clojure community should have just published to central. But even there, I don't know, maybe if you own the domain, you can make a claim that you "lost your password"
and again, you're not in control, you can depend on some lib that doesn't own his accounts everywhere and get bit by it
it's also quite obscure so not everybody is aware of that issue vs good credentials management for git host
Good credentials management + being impervious to social engineering + vetting the deps of that library on Git.
a "simple" fix would be to have the ability to specify :mvn/repo in dep coords, but given how it's implemented it's not easy (it relies on java libs that do not support this afaik)
Ya, I see the concern. It's a good point. Domain expiry does seem like a more common than you'd think occurence
Ya, specifying the mvn/repo per dep would solve it a bit. But you could still hijack if you have the domain. I guess maybe the repo won't let you claim the same domain on a different account
there are credentials on the existing account, you need that to hijack on a repo where it exists already
Right, so the issue really shows up in Clojure because of our use of Clojars as well as Central
I've never seen another one? Isn't both Maven and Gradle only setup to check central ?
I use https://github.com/slipset/deps-deploy + tools.build. Here's an example: • deps alias: https://github.com/phronmophobic/clj-graphviz/blob/26dbd8afdca3f8a37b60bde1d6a59a68054f851a/deps.edn#L67 • build.clj: https://github.com/phronmophobic/clj-graphviz/blob/26dbd8afdca3f8a37b60bde1d6a59a68054f851a/build.clj#L33 • bonus! github workflow: https://github.com/phronmophobic/clj-graphviz/blob/26dbd8afdca3f8a37b60bde1d6a59a68054f851a/.github/workflows/deploy-clojars.yml (this requires adding your clojars credentials as github repo secrets).
From our deps.edn
at work, tools using Clojars versions (mostly "RELEASE"
to get the most recent stable version):
• antq, jedi-time, dbxray, clojure-lsp
> Make your Clojure library build process easy. wonder if the authors've seen that rich hickey talk…